方法引用其实就是 Lambda 表达式的语法糖
方法引用本质上就是一个【函数指针】function pointer
注意: 方法调用和方法引用没有半毛钱关系,如果学过 JavaScript 就类似于使用函数变量地址值的传递。
方法引用分4类:
我们先建个类,用于对象排序。
package cn.zxhysy.jdk8.methodreference;
import java.util.List;
public class Student {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
/** 排序方法 */
public static int compareStudentByScore(Student student1, Student student2){
return student1.score - student2.score;
}
/** 根据名字字符比较 */
public static int compareStudentByName(Student student1, Student student2){
return student1.getName().compareToIgnoreCase(student2.getName());
}
}
类名::静态方法名 替换 Lambda 表达式,要求要类中有一个方法体跟 Lamdba 表达式是客观等价的,就可以被引用。也就是参数列表一致(参数值,参数类型,返回值一致)。
package cn.zxhysy.jdk8.methodreference;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class MethodReferenceTest {
public static void main(String[] args) {
Student student1 = new Student("zhangsan",10);
Student student2 = new Student("lisi",90);
Student student3 = new Student("wangwu",60);
Student student4 = new Student("zhaoliu",30);
List<Student> students = Arrays.asList(student1,student2,student3, student4);
// 调用写好的静态排序
students.sort((s1, s2) -> Student.compareStudentByScore(s1,s2));
students.sort(Student::compareStudentByScore);
students.forEach(student -> System.out.println(student.getName()));
System.out.println("----------------");
// 将调用的静态排序改成方法引用
students = Arrays.asList(student1,student2,student3, student4);
students.sort(Student::compareStudentByScore);
students.forEach(student -> System.out.println(student.getName()));
}
}
引用名::实例方法名 替换 Lambda 表达式,要求要实例中有一个方法体跟 Lamdba 表达式是客观等价的,就可以被引用。也就是参数列表一致(参数值,参数类型,返回值一致)。与 类::静态方法名 一样。
这里我们需要先建一个补助类,用来放排序的方法,非静态
package cn.zxhysy.jdk8.methodreference;
import java.util.Arrays;
import java.util.List;
public class StudentComparator {
/** 排序方法 */
public int compareStudentByScore(Student student1, Student student2){
return student1.getScore() - student2.getScore();
}
/** 根据名字字符比较 */
public int compareStudentByName(Student student1, Student student2){
return student1.getName().compareToIgnoreCase(student2.getName());
}
}
进行测试:
package cn.zxhysy.jdk8.methodreference;
import java.util.Arrays;
import java.util.List;
public class MethodReferenceTest2 {
public static void main(String[] args) {
Student student1 = new Student("zhangsan",10);
Student student2 = new Student("lisi",90);
Student student3 = new Student("wangwu",60);
Student student4 = new Student("zhaoliu",30);
List<Student> students = Arrays.asList(student1,student2,student3, student4);
StudentComparator studentComparator = new StudentComparator();
// 使用 Lambda 表达式实现
students.sort((s1 , s2) -> studentComparator.compareStudentByName(s1, s2));
students.forEach(student -> System.out.println(student.getName()));
System.out.println("----------------");
// 使用 对象名::实例方法名 引用
students = Arrays.asList(student1,student2,student3, student4);
students.sort(studentComparator::compareStudentByName);
students.forEach(student -> System.out.println(student.getName()));
}
}
·这个比较核心。先说下,我们在Student类中定义的两个静态方法,其实从设计上看,是很有问题的,对象本身就有数据了,还要再接受两个数据给他来比较。应该这样设计,设计一个实例方法,传递一个对象进来,与自己本身对象的属性进行比较后返回值。
根据上面设计,在Student类中添加下面一段代码:
public int compareByScope(Student student){
return this.getScore() - student.getScore();
}
public int compareByName(Student student){
return this.getName().compareToIgnoreCase(student.getName());
}
测试:
package cn.zxhysy.jdk8.methodreference;
import java.util.Arrays;
import java.util.List;
public class MethodReferenceTest3 {
public static void main(String[] args) {
Student student1 = new Student("zhangsan",10);
Student student2 = new Student("lisi",90);
Student student3 = new Student("wangwu",60);
Student student4 = new Student("zhaoliu",30);
List<Student> students = Arrays.asList(student1,student2,student3, student4);
// 使用 Lambda 表达式进行比较
students.sort((s1, s2) -> s1.compareByName(s2));
students.forEach(student -> System.out.println(student.getName()));
System.out.println("----------------");
// 使用 类名::实例方法名 引用
students = Arrays.asList(student1,student2,student3, student4);
students.sort(Student::compareByName);
students.forEach(student -> System.out.println(student.getName()));
}
}
看到这里,大家应该有疑惑 compareByName()方法只接受一个参数,那sort() 需要的是两个参数,根本对不上。我们就需要理清楚到底是谁调用了compareByName 方法,类名肯定调用不了。我们知道,实例方法是由对象调用的,那么有可能的就是 sort 方法里面的参数调用了该方法,与另一个参数对比。
事实上,compareByName 是由 sort 方法的第一个参数进行调用,之后 sort 方法的所有参数,作为 compareByName 方法参数。
类::实例方法引用,原理上就是 引用处的第一个参数作为对象调用实例方法,其他参数,则作为实例方法的参数。
构造方法本身是可以重载的,但编译工具在引用时自己会识别的。
package cn.zxhysy.jdk8.methodreference;
import java.util.function.Function;
import java.util.function.Supplier;
public class MethodRefernceTest4 {
public String getString(Supplier<String> supplier){
return supplier.get() + "test";
}
public String getString(String str, Function<String, String> function){
return function.apply(str);
}
public static void main(String[] args) {
MethodRefernceTest4 methodRefernceTest4 = new MethodRefernceTest4();
System.out.println(methodRefernceTest4.getString(String :: new));
// 带参数
System.out.println(methodRefernceTest4.getString("hello", String::new));
}
}
这里,推荐使用 idea 编程工具,在对 lambda 表达式的支持上相当给力,可以给你的代码提供优化的选择方案,让你的代码更为漂亮。