方法引用与构造器引用
使用场景
如果要传递给Lambda方法体的内容,已经有方法实现了,这时我们就可以使用“方法引用”了。我们也可以理解为,方法引用是Lambda表达式的另一种表现形式
方法引用
注意使用方法引用的前提:你需要实现的接口中的抽象方法的参数列表和返回值类型与我们Lambda体中当前调用的方法的参数列表和返回值类型保持一致
方法引用主要有三种语法格式:
对象::实例方法名
/**
* 对象::实例方法名
*/
@Test
public void test01(){
//不使用方法引用
Consumer<String> consumer = (x) -> System.out.println(x);
PrintStream ps = System.out;
//对象调实例方法
Consumer<String> consumer2 = (x) -> ps.println(x);
//当Lambda体中的功能已经有方法实现了的时候就可以使用方法引用了 即 对象::实例方法名
Consumer<String> consumer3 = ps::println;
consumer.accept("这是参数");
consumer2.accept("这是参数");
consumer3.accept("这是参数");
}
运行结果
这是参数
这是参数
这是参数
说明这三种是一样的效果,也就是当Lambda体中的功能已经有方法完成了的时候,就可以选择用方法引用的方式来写。这样用对象::实例方法名就更简洁了。
下面我们再来看一个例子,当Lambda体中的功能已经有方法实现了的时候就可以使用方法引用了
@Test
public void test02(){
//不适用方法引用
Employee employee = new Employee();
employee.setName("姓名");
Supplier<String> supplier = () -> employee.getName();
String str = supplier.get();
//当Lambda体中的功能已经有方法实现了的时候就可以使用方法引用了 employee::getName
Supplier<String> supplier2 = employee::getName;
String str2 = supplier2.get();
System.out.println(str);
System.out.println(str2);
}
运行结果
姓名
姓名
Employee类如下:
public class Employee {
private String name;
private int age;
private double salary;
public Employee(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public Employee() {
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
类::静态方法名
当类中的方法为静态方法时,方法引用可以直接使用类::静态方法名
@Test
public void test03(){
Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);
//Integer中的compare是静态方法 静态方法可以直接用类名引用
Comparator<Integer> comparator2 = Integer::compare;
int result = comparator.compare(5,4);
int result2 = comparator.compare(5,4);
System.out.println(result);
System.out.println(result2);
}
我们来看一下Integer中的compare方法
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
我们再来看一下Comparator接口中的compare方法
int compare(T o1, T o2);
Integer中的compare方法为static静态方法,且Integer中的compare方法和Comparator接口中的compare方法,参数列表和返回值类型都相同,所以可以直接使用方法引用Integer::compare
类::实例方法名
这种格式的使用前提是当Lambda表达式参数列表的第一个参数是你这个实例方法的调用者,第二个参数是你要调用的实例方法的参数时可使用ClassName::method这种格式
/**
* 类::实例方法名
*/
@Test
public void test04(){
//BiPredicate接口是Predicate接口的子接口,可以传俩参数
BiPredicate<String,String> predicate = (x,y) -> x.equals(y);
//当Lambda表达式参数列表的第一个参数是你这个实例方法的调用者,第二个参数是你要调用的实例方法的参数时,
// 可使用ClassName::method这种格式
BiPredicate<String,String> predicate2 = String::equals;
}
构造器引用
构造器引用的语法格式是ClassName::new
注意:需要调用的构造器的参数列表与函数式接口中抽象方法的参数列表要保持一致
/**
* 构造器引用
*/
@Test
public void test05(){
//此时调用的是Employee类中无参数的构造方法
Supplier<Employee> supplier = () -> new Employee();
//构造器引用
Supplier<Employee> supplier2 = Employee::new;
Employee e1 = supplier.get();
//此时调用的是Employee类中一个参数的构造方法
Function<Integer,Employee> function = (x) -> new Employee(x);
Employee e2 = function.apply(18);
Function<Integer,Employee> function2 = Employee::new;
Employee e3 = function2.apply(20);
System.out.println(e1);
System.out.println(e2);
System.out.println(e3);
}
由于构造器的参数列表要与接口中抽象方法的参数列表保持一致,所以Employee::new对应的是哪个构造方法,要看接口中抽象方法的参数列表是几个参数。
数组引用
数组引用的语法格式是 Type[]::new 下面我就通过一个简单例子使用一下数组引用。
/**
* 数组引用
*/
@Test
public void test06(){
Function<Integer,String[]> function = (x) -> new String[x];
String[] strs = function.apply(10);
System.out.println(strs.length);
Function<Integer,String[]> function2 = String[]::new;
String[] strs2 = function2.apply(20);
System.out.println(strs2.length);