前言
前面两篇关于Java8新特性的文章,主要介绍了Lambda表达式、函数式接口以及内置函数的知识,这一篇博文主要总结了Lambda中方法引用和构造器引用的知识。每天学习一小步,就是你技术成长之路的一大步。
方法引用
什么叫做方法引用呢?
如果Lambda体中的内容,有方法已经实现了,这时,我们就可以使用方法引用。
就以下面代码为例:
@Test
public void test1() {
Consumer<String> consumer = (x) -> System.out.println(x);
PrintStream out = System.out;
Consumer<String> con = out::println;
Consumer<String> con1 = System.out::println;
con1.accept("hello");
}
上面代码,实际上效果都是一样。这里就将System.out.println(x);写成了System.out::println;这种形式。
因为System.out返回的是PrintStream这个对象,同时,println()这个方法是实例方法,那么就可以使用对象::方法名这种形式,来书写Lambda。
这里的注意事项:
调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的参数列表和返回值类型保持一致。
方法引用有三种表现形式:
①:对象::实例方法名
②:类::静态方法名
③:类::实例方法名
下面就用代码分别演示这三种表现形式。
对象::实例方法名
@Test
public void test2() {
Book book = new Book("程序员的自我修养", 555D, "清风", 1L);
Supplier<String> supplier = () -> book.getBookName();
String str = supplier.get();
System.out.println(str);
Supplier<Double> supplier1 = book::getPrice;
System.out.println(supplier1.get());
}
这里就以获取书名为例,首先保证调用方法的参数列表和返回值类型,与函数式接口中抽象方法的参数列表和返回值一致。然后在决定使用哪一种形式即可。代码中写了两种形式,就是为了方便大家区分。
类::静态方法名
public void test3() {
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
Comparator<Integer> com1 = Integer::compare;
}
因为compare()这个方法是静态方法,所以,直接使用类名调用即可,这里和静态方法的调用有异曲同工之处。
类::实例方法名
@Test
public void test4() {
BiPredicate<String, String> bp1 = (x, y) -> x.equals(y);
BiPredicate<String, String> bp2 = String::equals;
}
这里也许会有些许疑惑,equals方法并非静态方法,也可以使用类名直接调用吗?
这里的注意事项:
如果Lambda参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::method。
由此可以看到,Lambda很大程度加快了开发的效率,也优化了程序员的体验度,新特性也加强了Java。
构造器引用
上面说了方法引用,下面再说说构造器引用,对应的表现形式是:ClassName::new
public void test5() {
Supplier<Book> supplier = () -> new Book();
//构造器引用
Supplier<Book> supplier1 = Book::new;
}
上面代码,就是在Lambda体中创建了一个Book对象,然后Supplier供给型函数式接口就能将其返回。为了简化书写,可以使用下面这种方式。直接 类名::new。
有些人可能到这里会产生疑惑。如果我有很多构造器,且参数列表不同,Lambda如何区分用的是哪个构造方法呢?
相信通过下面的代码,就能解决大家的疑惑。
@Test
public void test6() {
Function<Integer, Employee> function = (x) -> new Employee(x);
//调用一个参数的构造函数
Function<Integer, Employee> function1 = Employee::new;
Employee apply = function1.apply(18);
System.out.println(apply);
//调用两个参数的构造函数
BiFunction<String, Double, Employee> function2 = Employee::new;
}
前篇博文,我们讲了Function<T,R>这个核心内置函数,它的作用是接收一个T类型的参数,返回一个R类型的值。对应方法:R apply(T t);
这样正好和Employee含有一个参数的构造函数相对应。BiFunction这个函数则是调用含有两个参数的构造方法。如果使用IDEA的读者,可以通过点击Ctrl+鼠标左键,就能跳转到对应的方法上。
这里的注意事项:
调用构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致。
数组引用
除了上面说的方法引用、构造器引用,还提供了数组引用。对应的表现形式是:Type::new;
因为这个理解起来也很容易,直接上代码。
@Test
public void test7() {
Function<Integer, String[]> function = (x) -> new String[x];
String[] apply = function.apply(10);
System.out.println(apply.length);
Function<Integer, Book[]> function1 = Book[]::new;
Book[] books = function1.apply(5);
System.out.println(books.length);
}
总结:整篇博文介绍了方法引用、构造器引用和数组引用的使用方法及注意事项,总而言之,Lambda使用起来还是高效和便捷的。
既然无法得到,就将它彻底毁掉!