Method Reference 是什么?
Method Reference 是Java 8 才开始提供的新特性, 翻译过来是方法引用。
其定义就是: 把已经定义好的名字和方法, 当做Lambda 表达式来使用。
官方给出的解释是: They are compact, easy-to-read lambda expressions for methods that already have a name.
Method Reference 的常用语法是 : className::methodName
Method Reference 使用示例
有如下用户类:
public class Usr {
private String name;
public Usr(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static int compareByName(Usr u1,Usr u2) {
return u1.name.compareTo(u2.name);
}
}
该类有一个name 的属性 和一个静态方法 compareByName(), 该方法用于根据name比较两个Usr对象。
对以上Usr类型的数组进行排序可以使用如下写法:
@Test
public void methodRef() {
Usr[] usrArray = new Usr[] { new Usr("张飞"), new Usr("关羽"), new Usr("刘备") };
Arrays.sort(usrArray, Usr::compareByName);
Assert.assertTrue(usrArray[0].getName().equals("关羽"));
}
Method Reference 的演化过程
Method Reference 其实对应的是Lambda 表达式, 其是如何一步步演变成 className::methodName
的呢? 同样以上面的例子来演示。
不使用Lambda 表达式的写法
@Test
public void withoutMethodRef2() {
Usr[] usrArray = new Usr[] { new Usr("张飞"), new Usr("关羽"), new Usr("刘备") };
Arrays.sort(usrArray, new Comparator<Usr>() {
@Override
public int compare(Usr o1, Usr o2) {
return Usr.compareByName(o1, o2);
}
});
Assert.assertTrue(usrArray[0].getName().equals("关羽"));
}
这里使用匿名内部类的方式创建了一个实现Comparator接口的类, 并且实现了其中的compare() 方法。
演进: Lambda 表达式
如果不使用方法引用, 使用Lambda 的写法如下:
@Test
public void lambda2() {
Usr[] usrArray = new Usr[] { new Usr("张飞"), new Usr("关羽"), new Usr("刘备") };
Arrays.sort(usrArray, (Comparator<Usr>) (Usr u1,Usr u2) -> { return Usr.compareByName(u1, u2);});
Assert.assertTrue(usrArray[0].getName().equals("关羽"));
}
(Usr u1,Usr u2)
参数, 定义了两个Usr 类型的参数{ return u1.getName().compareTo(u2.getName());}
方法体返回一个整型的数字
继续演进
因为Usr.compareByName(u1, u2)
已经定义了输入和输出, 所以左边的参数可以省略。于是
(Usr u1,Usr u2) -> { return Usr.compareByName(u1, u2);
=> Usr::compareByName
总结: 所谓的方法引用, 就是可以将方法看成是一个对象, 引用这个对象, 参数不需要写, 使用 ::
, 这个可以也结合js 中的方法对象来理解。
方法引用的类型
以上演示的是静态方法引用, 其实包括静态方法, 可以引用的方法包括:
ClassName::staticMethodName
静态方法引用ClassName::new
构造方法引用instanceReference::instanceMethodName
实例上的实例方法引用ClassName::instanceMethodName
类型上的实例方法
备注
此处对象数组的比较仅用于演示, 一般状况很少在实体类中定义静态比较方法, 常见的比较方式如下:
@Test
public void withoutMethodRef() {
Usr[] usrArray = new Usr[] { new Usr("张飞"), new Usr("关羽"), new Usr("刘备") };
Arrays.sort(usrArray, new Comparator<Usr>() {
@Override
public int compare(Usr o1, Usr o2) {
return o1.getName().compareTo(o2.getName());
}
});
Assert.assertTrue(usrArray[0].getName().equals("关羽"));
}
@Test
public void lambda() {
Usr[] usrArray = new Usr[] { new Usr("张飞"), new Usr("关羽"), new Usr("刘备") };
Arrays.sort(usrArray, (Comparator<Usr>) (Usr u1,Usr u2) -> { return u1.getName().compareTo(u2.getName());});
Assert.assertTrue(usrArray[0].getName().equals("关羽"));
}