一、什么是方法引用
方法引用就是,当要传递给Lambda体的操作,已经有实现的方法了,就可以使用方法引用
方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖
要求:实现接口的抽象方法体的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致
使用操作符 ::
将类(或对象)与方法名分割开来
主要分为下面三种使用情况:
- 对象 :: 实例方法名
- 类 :: 静态方法名
- 类 :: 实例方法名
二、几种实例
准备一个 Employee 对象的 JavaBean
public class Employee {
private int id;
private String name;
private int age;
private double salary;
// getter/setter 方法
}
1. 对象 :: 实例方法名
@Test
public void test1() {
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
// 此时方法引用中的参数也省略,因为和抽象方法中的参数一样,所以可以直接省略
Consumer<String> consumer2 = System.out::println;
consumer2.accept("陈磊是傻逼");
}
因为方法 void println(String x)
和接口中重写的方法体 void println(String s)
的形参列表和返回值类型都相同,所以直接用 void println(String x)
方法替代接口中的抽象方法,调用 println 方法的对象是 System.out,实例方法便是 println,此时不需要在后面跟参数,因为 println() 方法的形参列表和 accept() 的形参列表一样,所以此时的方法引用 println 后面的参数可以直接省略
@Test
public void test2() {
Employee employee = new Employee(10, "陈磊");
Supplier<String> supplier = new Supplier<String>() {
// 此时 String getName() 和 String get() 方法类似
@Override
public String get() {
return employee.getName();
}
};
Supplier<String> supplier2 = employee::getName;
System.out.println(supplier2.get());
}
此时方法 String getName()
和接口中抽象方法 String get()
的形参列表和返回值类型都相同,所以可以直接用 对象 :: 实例方法
的形式来简化,这里的对象是 employee,实例方法是 getName
2. 类 :: 静态方法
可以使用 类 :: 静态方法
的形式来作为抽象方法体的引用
@Test
public void test3() {
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
};
System.out.println(comparator.compare(10, 20));
// 使用 Lambda 表达式
Comparator<Integer> comparator1 = (o1, o2) -> o1.compareTo(o2);
System.out.println(comparator1.compare(10, 20));
// 使用 Lambda 表达式和类的静态变量
Comparator<Integer> comparator2 = (o1, o2) -> Integer.compare(o1, o2);
System.out.println(comparator2.compare(10, 20));
// 使用静态方法引用
Comparator<Integer> comparator3 = Integer::compare;
System.out.println(comparator3.compare(10, 20));
}
此时抽象方法体 int compareTo(Integer a)
可以转换成调用 Integer 的静态方法 int compare(int x, int y)
写成的 Lambda 表达式,而该 Lambda 表达式又可以转换成使用静态方法引用的格式
@Test
public void test4() {
Function<Double,Long> function = new Function<Double, Long>() {
@Override
public Long apply(Double aDouble) {
return Math.round(aDouble);
}
};
System.out.println(function.apply(5.6));
Function<Double, Long> function1 = aDouble -> Math.round(aDouble);
System.out.println(function1.apply(5.7));
Function<Double, Long> function2 = Math::round;
System.out.println(function2.apply(5.8));
}
3. 类 :: 实例方法
@Test
public void test6() {
BiPredicate<String,String> biPredicate = new BiPredicate<String, String>() {
@Override
public boolean test(String s, String s2) {
return s.contentEquals(s2);
}
};
BiPredicate<String, String> biPredicate1 = String::contentEquals;
}
需要注意的是,当函数式接口方法的第一个参数是需要引用方法的调用者,并且第二个参数是需要引用方法的参数(或无参数)时,可以使用 ClassName :: methodName
这样的来引用
这里的函数式接口方法是 boolean test(String s,String s2)
,其中的实现方法是用 s 调用 contentEquals(s2)
方法,而 boolean contentEquals(CharSequence cs)
表示使用 String 类型的参数来调用 contentEquals 方法,并返回 boolean 类型的值
三、构造器引用
可以把构造器引用赋值给定义的方法,要求构造器参数列表要与接口中抽象方法的参数列表一致,且方法的返回值即为构造器对应类的对象
格式:ClassName::new
public void test1(){
Supplier<Employee> supplier = new Supplier<Employee>() {
@Override
public Employee get() {
// 返回一个构造器
return new Employee();
}
};
Supplier<Employee> supplier1 = () -> new Employee();
Supplier<Employee> supplier2 = Employee::new;
}
@Test
public void test2(){
Function<Integer,Employee> function = new Function<Integer, Employee>() {
@Override
public Employee apply(Integer integer) {
// 构造器参数列表和接口中抽象方法的参数列表一致,且抽象方法的返回值也是构造器对应类的对象
return new Employee(integer);
}
};
Function<Integer, Employee> function1 = integer -> new Employee(integer);
Function<Integer, Employee> function2 = Employee::new;
}
四、数组引用
格式:type[] :: new
@Test
public void test4(){
Function<Integer,String[]> function = new Function<Integer, String[]>() {
@Override
public String[] apply(Integer integer) {
return new String[integer];
}
};
Function<Integer, String[]> function1 = integer -> new String[integer];
Function<Integer, String[]> function2 = String[]::new;
}