Java8特性一
接口的default
(虚拟扩展方法)
interface Calculate {
double cal(int a);
// 通过使用 default 关键字向接口添加非抽象方法实现。
default double sqrt(int a) {
return Math.sqrt(a);
}
}
public class Demo {
public static void main(String[] args) {
// 匿名内部类方式
Calculate calculate = new Calculate() {
@Override
public double cal(int a) {
return sqrt(a*100);
}
};
System.out.println(calculate.cal(100)); // 100.0
System.out.println(calculate.sqrt(100)); // 10.0
}
}
Lambda
public class Demo {
public static void main(String[] args) {
List<String> names = Arrays.asList("lei","ya","di");
names.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
System.out.println(names); // [di, lei, ya]
}
}
在IDEA中,会自动提示用lambda替换:
public class Demo {
public static void main(String[] args) {
List<String> names = Arrays.asList("lei","ya","di");
names.sort((o1, o2) -> o1.compareTo(o2));
System.out.println(names); // [di, lei, ya]
}
}
仍提示可以替换:
public class Demo {
public static void main(String[] args) {
List<String> names = Arrays.asList("lei","ya","di");
names.sort(String::compareTo);
System.out.println(names); // [di, lei, ya]
}
}
用 lambda 表达式创建匿名方法,有时候, lambda 表达式仅用于调用现有方法而不做其他事,就可以用方法引用来调用方法
Lambda作用域
对lambda表达式中的实例字段和静态变量都有读写访问权限。无法从 lambda 表达式中访问默认方法。
方法引用
public class Demo {
public interface Say {
void run();
}
public void invoke(Say say) {
System.out.println(say.getClass().getName());
}
public static void main(String[] args) {
Demo demo = new Demo();
System.out.println("==== new SayHello() =====");
demo.invoke(new SayHello()); // 接口实现类
System.out.println("\n==== lambda =====");
demo.invoke(()-> System.out.println("Hello")); // lambda
System.out.println("\n==== new SayHello()::run =====");
demo.invoke(new SayHello()::run); // 引用方法
System.out.println("\n==== SayHello::new =====");
demo.invoke(SayHello::new); // SayHello::new 引用的是构造函数
}
}
class SayHello implements Demo.Say {
public SayHello() {
System.out.println("SayHello 构造方法");
}
@Override
public void run() {
System.out.println("hello");
}
}
输出:
==== new SayHello() =====
SayHello 构造方法
java8.SayHello
==== lambda =====
java8.Demo$$Lambda$1/1078694789
==== new SayHello()::run =====
SayHello 构造方法
java8.Demo$$Lambda$2/1149319664
==== SayHello::new =====
java8.Demo$$Lambda$3/999966131
Process finished with exit code 0
后三个都是匿名方法,而且,只有new
了才会调用构造函数。
更改invoke
函数:
public void invoke(Say say) {
System.out.println(say.getClass().getName());
say.run();
}
得到:
==== new SayHello() =====
SayHello 构造方法
java8.SayHello
hello
==== lambda =====
java8.Demo$$Lambda$1/1078694789
Hello
==== new SayHello()::run =====
SayHello 构造方法
java8.Demo$$Lambda$2/1149319664
hello
==== SayHello::new =====
java8.Demo$$Lambda$3/999966131
SayHello 构造方法
Process finished with exit code 0
一个不错的例子:对象工厂
class Person {
String name;
int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
}
}
interface PersonFactory<P extends Person> {
P create(String name,int age);
}
public class Demo {
public static void main(String[] args) {
// 方法引用,这里的create就指向了Person的构造函数
// 具体哪个根据参数来选择
PersonFactory<Person> personFactory = Person::new;
Person person = personFactory.create("aa",13);
System.out.println(person); // Person{name='aa', age=13}
}
}
函数式接口
仅仅包含一个抽象方法,但是可以有多个非抽象方法(default)。
public class Demo {
// 不必须,函数式接口,只包含一个抽象方法
@FunctionalInterface
public interface Say {
void run();
}
public static void main(String[] args) {
Say say = () -> System.out.println("hi");
say.run(); // hi
}
}
Supplier
接口
public class Demo {
// Supplier接口指定什么泛型,就可以使用get方法,生产什么类型的数据
public static int getMax(Supplier<Integer> supplier) {
return supplier.get();
}
public static void main(String[] args) {
int[] arr = {1,5555,999,-90,1314};
int max = getMax(()->{
int m = arr[0];
for (int i = 1; i < arr.length; i++) {
if(arr[i] >m) {
m = arr[i];
}
}
return m;
});
System.out.println(max); // 5555
}
}
Consumer
接口
这个是给一个参数到 lambda类的函数去处理,可以和andThen
连用。
public class Demo {
public static void print(String s, Consumer<String> consumer1,Consumer<String> consumer2) {
consumer1.andThen(consumer2).accept(s);
}
public static void main(String[] args) {
print("di",s -> {
System.out.println(s+"run");
},s -> {
System.out.println(s+"eat");
});
// dirun
//dieat
}
}
Function
接口
public class Demo {
public static int cal(String s, Function<String,Integer> f1,
Function<Integer,Integer> f2) {
return f1.andThen(f2).apply(s);
}
public static void main(String[] args) {
System.out.println(cal("66", Integer::parseInt,
integer -> integer*2+1)); // 133
}
}
Predicate
接口
import java.util.function.Predicate;
public class Demo {
public static void check(String s, Predicate<String> predicate) {
System.out.println(predicate.test(s));
}
public static void main(String[] args) {
check("abc",s-> s.contains("a")); // true
}
}
Streams
package java8;
import java.util.*;
public class Demo {
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
stringList.add("ddd2");
stringList.add("aaa2");
stringList.add("bbb1");
stringList.add("aaa1");
stringList.add("bbb3");
stringList.add("ccc");
stringList.add("bbb2");
stringList.add("ddd1");
stringList
.stream()
.filter(s->s.startsWith("a"))
.forEach(System.out::println);
// aaa2
// aaa1
// 排序是一个 中间操作,返回的是排序好后的 Stream。如果你不指定一个自定义的 Comparator 则会使用默认排序。
stringList
.stream()
.sorted()
.filter(s->s.startsWith("a"))
.forEach(System.out::println);
// aaa1
// aaa2
// 中间操作 map 会将元素根据指定的 Function 接口来依次将元素转成另外的对象。
stringList
.stream()
.map(String::toUpperCase)
.sorted(Comparator.reverseOrder())
.forEach(System.out::println);
// DDD2
// DDD1
// CCC
// ...
// Stream提供了多种匹配操作,允许检测指定的Predicate是否匹配整个Stream。
// 所有的匹配操作都是 最终操作 ,并返回一个 boolean 类型的值。
System.out.println(
stringList
.stream()
.anyMatch(s -> s.startsWith("a"))); // true
System.out.println(
stringList
.stream()
.allMatch(s -> s.startsWith("a"))); //false
System.out.println(
stringList
.stream()
.noneMatch(s -> s.startsWith("a"))); //false
// count最终操作,返回个数
System.out.println(
stringList
.stream()
.filter(s -> s.startsWith("a"))
.count()); //2
// reduce 这是一个 最终操作 ,允许通过指定的函数来将stream中的多个元素规约为一个元素
System.out.println(
stringList
.stream()
.sorted()
.reduce(((s, s2) -> s+"#"+s2)));
// Optional[aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2]
int[] ints = {1,4,2,5,6,3,2,10,9};
Optional<Integer> res = Arrays.stream(ints).boxed()
.reduce(Math::max);
res.ifPresent(System.out::println); //10
}
}
parallelStream()
并行排序,默认stream
是串行的。
Maps
public class Demo {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
for (int i = 0; i < 10; i++) {
map.putIfAbsent(i, "val" + i); //没有就放,有就返回值
}
map.forEach((id, val) -> System.out.println(val));
map.computeIfPresent(3,(num,val)->val+num); //val33
System.out.println(map.get(3));
}
}
Optional
解决空指针异常。就不用加一堆判断了。
具体看这篇文章:理解、学习与使用 JAVA 中的 OPTIONAL
参考
Java Lambda 表达式(四):方法引用(Method Reference)