一、方法引用
若Lambda体中的内容已经有方法实现过了,我们可以使用方法引用,使用方法引用的时候需要保证引用方法的参数列表和返回值类型与我们当前所要实现的函数式接口方法的参数列表和返回值类型保持一致。方法引用是Lambda表达式的另外一种表现形式。
方法引用的语法格式:
1、对象::实例方法名:示例中的几种方式是等效的
public void test1() {
Consumer<String> con = (x) -> System.out.println(x);
con.accept("Hello World!");
PrintStream ps = System.out;// 返回一个PrintStream对象
// System.out.println(x)在PrintStream的println方法中已经实现,可以使用方法引用
Consumer<String> con1 = ps::println;
con1.accept("Hello Lambda!");
Consumer<String> con2 = System.out::println;//匿名对象方法引用
con2.accept("Hello Lambda Method!");
}
println的实现:
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
供给型接口的方法引用:
Employee emp = new Employee();
emp.setName("WangJin");
Supplier<String> sup = emp::getName;
String name = sup.get();
System.out.println(name);
2、类::静态方法名:示例中的两种方式等价
public void test2() {
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
com.compare(1, 2);
// 使用方法引用的方式
Comparator<Integer> com1 = Integer::compare;
com1.compare(1, 2);
}
3、类::实例方法名: 需要函数式接口方法定义的第一个参数是对应类的实例对象,保证调用时的第一个参数(此时为abc)是方法的调用者,即调用方法的对象,后续的参数(此处即bcd)是方法的入参,也就是说在这种情况下Lambda表达式会将方法调用时的第一个参数当做调用方法的主体,这种方法引用的方式就不满足使用方法引用的时候需要保证引用方法的参数列表和返回值类型与我们当前所要实现的函数式接口方法的参数列表和返回值类型保持一致这一规则了,但此时第一个参数是实例方法的调用者,后续参数是方法的入参
public void test3() {
// BiPredicate是Java8的内置函数式接口
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
bp.test("abc", "bcd");
// 需要保证调用时的第一个参数(此时为abc)是方法的调用者,后续的参数(此处即bcd)是方法的入参
BiPredicate<String, String> bp1 = String::equals;
bp1.test("abc", "bcd");
}
示例2:
接口定义:
@FunctionalInterface
public interface SelfTestInterface<T, R> {
boolean nameCompare(T t, R r1, R r2);
}
方法定义:
public class Employee{
private String name;
public boolean nameCompare(String name1,String name2) {
return this.getName().equals(name1 + name2);
}
//...
}
方法引用:
public void test4() {
SelfTestInterface<Employee, String> test = Employee::nameCompare;
Employee emp = new Employee();
emp.setName("abc");
boolean nameCompare = test.nameCompare(emp, "a","bc");
System.out.println(nameCompare);
}
二、构造器引用
语法格式:ClassName::new,调用哪个构造器取决于函数式接口中的方法形参的定义,Lambda会自动根据接口方法的定义推断你要调用的构造器,也就是说需要调用的构造器的参数列表要与函数式接口中的抽象方法的参数列表保持一致
示例1:此时会调用Employee的无参构造器,因为Supplier接口的抽象方法没有入参
Supplier<Employee> sup = Employee::new;
Supplier的定义:
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
示例2:此时Employee中需要一个一个入参的构造器
Function<String,Employee> fun = Employee::new;
Function接口的定义:
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
...
}
Employee中的一个参数的构造器:
public Employee(String name) {
this.name = name;
}
三、数组引用
同构造器引用,格式为Type[]::new
public void test5() {
Function<Integer, String[]> fun = (x) -> new String[x];
fun.apply(10);
// 数组引用
Function<Integer, String[]> fun1 = String[]::new;
fun1.apply(20);
}