方法引用—Method Reference
是Lambda
表达式的语法糖
- 示例
public class MethodReferenceTest {
public static void main(String[] args) {
List<String> list = Arrays.asList("hello", "world", "hello world");
list.forEach(System.out :: println);
}
}
执行结果
hello
world
hello world
我们可以将方法引用看着是一个函数指针
—Function Pointer
1.方法引用的分类
方法引用分为四类
- 静态方法引用—
类名::静态方法名
- 示例方法引用
引用名(对象名)::实例方法名
- 类方法引用—
类名::实例方法名
- 构造方法引用—
类名::new
1.1 静态方法引用—类名::静态方法名
(className::staticMethod
)
其所使用的Lambda表达式恰好有一个静态方法完成与之相同的事情,则可将其替换为方法引用
- 实例
public class MethodReferenceTest {
public static void main(String[] args) {
Student student1 = new Student("zhangsan", 20);
Student student2 = new Student("lisi", 90);
Student student3 = new Student("wanwu", 30);
Student student4 = new Student("zhaoliu", 60);
List<Student> students = new ArrayList<>();
students.add(student1);
students.add(student2);
students.add(student3);
students.add(student4);
//使用lambda表达式
//通过成绩降序排序
students.sort((studentParam1, studentParam2)
-> Student.compareStudentByScore(studentParam2, studentParam1));
students.forEach(student -> System.out.println(student.getScore()));
System.out.println("+++++++");
//通过名字降序排序
students.sort((studentParam1, studentParam2)
-> Student.compareByScoreByName(studentParam2, studentParam1));
students.forEach(student -> System.out.println(student.getName()));
System.out.println("+++++++");
//使用方法引用
//通过成绩升序排序
students.sort(Student :: compareStudentByScore);
students.forEach(student -> System.out.println(student.getScore()));
System.out.println("+++++++");
//通过名字升序排序
students.sort(Student :: compareByScoreByName);
students.forEach(student -> System.out.println(student.getName()));
System.out.println("+++++++");
}
}
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.getScore()-student2.getScore();
}
public static int compareByScoreByName(Student student1, Student student2){
return student1.getName().compareToIgnoreCase(student2.getName());
}
}
执行结果
90
60
30
20
+++++++
zhaoliu
zhangsan
wanwu
lisi
+++++++
20
30
60
90
+++++++
lisi
wanwu
zhangsan
zhaoliu
+++++++
注意事项
虽然方法引用className::staticMethod
与className.staticMethod
执行的结果是一致的.但可以认为两者是没有任何关系
- 前者是方法引用的一种表达式形式,是函数指针,不能传递任何参数
- 后者不能作为单独的表达式存在,需要传递参数,表示方法调用
1.2 实例方法引用—引用名(对象名)::实例方法名
- 示例
public class MethodReferenceTest {
public static void main(String[] args) {
Student student1 = new Student("zhangsan", 20);
Student student2 = new Student("lisi", 90);
Student student3 = new Student("wanwu", 30);
Student student4 = new Student("zhaoliu", 60);
List<Student> students = new ArrayList<>();
students.add(student1);
students.add(student2);
students.add(student3);
students.add(student4);
StudentComparator comparator = new StudentComparator();
students.sort(comparator :: compareByScoreByName);
students.forEach(student -> System.out.println(student.getName()));
System.out.println("++++++++");
students.sort(comparator :: compareStudentByScore);
students.forEach(student -> System.out.println(student.getScore()));
}
}
public class StudentComparator {
public int compareStudentByScore(Student student1, Student student2){
return student1.getScore()-student2.getScore();
}
public int compareByScoreByName(Student student1, Student student2){
return student1.getName().compareToIgnoreCase(student2.getName());
}
}
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;
}
}
执行结果
isi
wanwu
zhangsan
zhaoliu
++++++++
20
30
60
90
1.3 类方法引用—类名::实例方法名
- 实例
public class MethodReferenceTest {
public static void main(String[] args) {
Student student1 = new Student("zhangsan", 20);
Student student2 = new Student("lisi", 90);
Student student3 = new Student("wanwu", 30);
Student student4 = new Student("zhaoliu", 60);
List<Student> students = new ArrayList<>();
students.add(student1);
students.add(student2);
students.add(student3);
students.add(student4);
students.sort(Student :: compareBySore);
students.forEach(student -> System.out.println(student.getScore()));
System.out.println("+++++++");
students.sort(Student::compareByName);
students.forEach(student -> System.out.println(student.getName()));
}
}
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 int compareBySore(Student student){
return this.score - student.getScore();
}
public int compareByName(Student student){
return this.name.compareToIgnoreCase(student.getName());
}
}
执行结果
20
30
60
90
+++++++
lisi
wanwu
zhangsan
zhaoliu
对于类方法引用存在一个疑问:
查看Comparator
函数接口源码可知,其接口int compare(T o1, T o2)
需传递两个参数
而Student
的compareBySore
和compareByName
方法只接收一个参数
那students.sort(Student :: compareBySore)
和students.sort(Student::compareByName)
是如何执行成功的呢?
我的猜测是答案就在Student
对象对应的字节码文件Student.class
中,通过jclasslib
查看两方法的LocalVaralbleTable
可知
Student
的compareBySore
和compareByName
方法的其实有两个参数,第一个是this
,第二个才是我们实际的传参student
那这样就能说通了
但查看String
对象对应的class文件,则跟上述猜测不一致,如下示例
- 示例
public class MethodReferenceTest {
public static void main(String[] args) {
List<String> cities = Arrays.asList("guangzhoug", "beijing", "chongqing", "shanghai");
Collections.sort(cities, String :: compareToIgnoreCase);
cities.forEach(city -> System.out.println(city));
}
}
执行结果
beijing
chongqing
guangzhoug
shanghai
通过jclasslib
查看String.class
中compareToIgnoreCase
方法的LocalVaralbleTable
可知,可惜compareToIgnoreCase
方法只有LineNumberTable
,没有LocalVaralbleTable
1.4 构造方法引用—类名::new
- 示例
public class MethodReferenceTest {
public String getString1(Supplier<String> supplier){
return supplier.get() + "test";
}
public String getString2(String str, Function<String, String> function){
return function.apply(str);
}
public static void main(String[] args) {
MethodReferenceTest test = new MethodReferenceTest();
System.out.println(test.getString1(String :: new));
System.out.println(test.getString2("hello", String :: new));
}
}
执行结果
test
hello