一、什么是方法引用?
当我们在写代码的时候,发现方法的入参是一个函数接口,比如我们在对数组进行排序,需要使用Arrays.sort(T[] a, Comparator<? super T> c)方法,此时Comparator是一个函数接口,在没有lambda的情况下,我们需要提供一个匿名内部类来实现Comparator接口,在Java 8中可以通过lambda表达式来实现,如果我们的代码中已经有一个类实现了Comparator接口,那么是否可以直接使用该类实现的compare方法呢?答案是可以的,这就是方法引用存在的意义,方法引用是用来直接访问类或者实例已经存在的方法或者构造方法,如果某个方法签名和接口恰好一致,就可以直接传入方法引用,恰好一致要求除了方法名外,方法参数一致且返回类型相同。计算时,方法引用会创建函数式接口的一个实例。
二、使用方法引用的好处?
1、方法引用的唯一用途是支持Lambda的简写。
2、方法引用提高了代码的可读性,也使逻辑更加清晰。
三、语法:
1、使用::操作符将方法名和类或者实例的名字分隔开
四、分类:
1、类名::静态方法名
2、对象::实例方法名
3、类名::实例方法名
4、类名::new
五、举例:
定义一个Student类:
import java.util.Arrays;import java.util.List;public class Student { private String name; private int score; public Student(){ } 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(); }}
现在有一批学生,需要我们按着分数由小到大排列并输出
1、首先我们使用lambda表达式的方式处理:
public static void main(String[] args) { Student student1 = new Student("zhangsan",60); Student student2 = new Student("lisi",70); Student student3 = new Student("wangwu",80); Student student4 = new Student("zhaoliu",90); List
2、【类名::静态方法名】此时我们发现Student类的compareStudentByScore方法与compare方法签名是一致的, 所有我们可以使用方法引用来改写:
public static void main(String[] args) { Student student1 = new Student("zhangsan",60); Student student2 = new Student("lisi",70); Student student3 = new Student("wangwu",80); Student student4 = new Student("zhaoliu",90); List
3、【对象::实例方法名】我们在Student里面增加一个实例方法,与静态方法一样:
public int compareStudent(Student student1,Student student2){ return student1.getScore() - student2.getScore(); }
然后我们代码可以这样写,这里用的是student1,其实用这四个中的任何一个都是可以的:
public static void main(String[] args) { Student student1 = new Student("zhangsan",60); Student student2 = new Student("lisi",70); Student student3 = new Student("wangwu",80); Student student4 = new Student("zhaoliu",90); List
4、【类名::实例方法名】我们从上面看,其实这个实例方法里面调用的时候,实例是知道自己的分数的,那是不是可以不用在定义方法的时候,只定义一个入参,而不是两个,也就是:
public int compareByScore(Student student){ return this.getScore() - student.getScore(); }
那要实现排序的需求,代码应该怎么写呢?
public static void main(String[] args) { Student student1 = new Student("zhangsan",60); Student student2 = new Student("lisi",70); Student student3 = new Student("wangwu",80); Student student4 = new Student("zhaoliu",90); List
现在我就有点困惑了,sort方法接收的lambda表达式不应该是两个参数么,为什么和int Comparator
5、【类名::new】我们来讲最后一个类型的用法,看下面这个问题,如果要把一个List
public Student(String name){ this.name = name; this.score = 0; }
传统的做法是先定义一个ArrayList
public static void main(String[] args) { List
要更简单地实现String到Student的转换,我们可以引用Student的构造方法:
public static void main(String[] args) { List
是不是有点奇怪,现在我们来看一下map()方法的入参FunctionalInterface的定义:
@FunctionalInterfacepublic interface Function
把泛型进行替换以后就是方法签名Student apply(String),即传入参数String,返回类型Student。而Student类的构造方法恰好满足这个条件,因为构造方法的参数是String,虽然构造方法虽然没有return语句,但它会隐式地返回this实例,类型就是Student,因此,此处可以引用构造方法。
六、总结:
1、方法引用是为了简化lambda表达式而出现的
2、类名::实例方法名 比较特殊,需要注意一下,会隐式的传入对象本身