Java 8 官方教程翻译——方法引用(method reference)

你可能会使用lambda表达式创建匿名方法。然而有时lambda表达式仅仅调用了一个已存在的方法。这种情况下,直接使用该方法名会显得更加简洁。方法引用正是用在此处;他们是有名方法的紧凑而又易读的lambda表达式。

回顾在Lambda Expressions一节中讨论过的Person类:
 
    
public class Person {
 
public enum Sex {
MALE, FEMALE
}
 
String name;
LocalDate birthday;
Sex gender;
String emailAddress;
 
public int getAge() {
// ...
}
public Calendar getBirthday() {
return birthday;
}
 
public static int compareByAge(Person a, Person b) {
return a.birthday.compareTo(b.birthday);
}}
假设社交网络应用程序中的成员信息使用数组进行存储,现在你需要按成员年龄将数组排序。那么你可以使用如下代码:
 
    
Person[] rosterAsArray = roster.toArray(new Person[roster.size()]);
 
class PersonAgeComparator implements Comparator<Person> {
public int compare(Person a, Person b) {
return a.getBirthday().compareTo(b.getBirthday());
}
}
Arrays.sort(rosterAsArray, new PersonAgeComparator());
该sort方法的签名如下:
 
    
static <T> void sort(T[] a, Comparator super T> c)
我们注意到Comparator接口是一个函数接口,因而可以使用lambda表达式取而代之,从而避免了需要定义一个实现Comparator的类并且对之实例化。
 
    
Arrays.sort(rosterAsArray,
(Person a, Person b) -> {
return a.getBirthday().compareTo(b.getBirthday());
}
);
然而,按照年龄比较两个Person实例的方法已经存在于Person类中,因此可以直接在lambda表达式中调用:
 
    
Arrays.sort(rosterAsArray,
(a, b) -> Person.compareByAge(a, b)
);
因为这个lambda表达式调用了一个已存在的方法,因而可以使用方法引用替换这个lambda表达式:
 
    
Arrays.sort(rosterAsArray, Person::compareByAge);
方法引用Person::CompareByAge和lambda表达式(a, b) -> Person.compareByAge(a, b)在语意上是等价的。分别都具有以下的特征:
  • 形式参数列表与Comparator.campare相同,(Person, Person)
  • 方法体调用了Person.compareByAge方法。

方法引用的类型
共有四种方法引用:
Kind Example
对静态方法的引用 ContainingClass::staticMethodName
对特定对象的实例方法的引用 containingObject::instanceMethodName
对特定类型的任意对象的实例方法的引用 ContainingType::methodName
对构造方法的引用 ClassName::new

对静态方法的引用
Person::compareByAge就是一个静态方法引用

对特定对象的实例方法的引用
下面的实例,展示了对特定对象的实例方法的引用:
 
    
class ComparisonProvider {
public int compareByName(Person a, Person b) {
return a.getName().compareTo(b.getName());
}
public int compareByAge(Person a, Person b) {
return a.getBirthday().compareTo(b.getBirthday());
}
}
ComparisonProvider myComparisonProvider = new ComparisonProvider();
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);
方法引用myComparisonProvider::compareByName调用了对象myComparisonProvider的方法compareByName。Java运行时推倒出了方法的类型参数,为(Person, Person)。

对特定类型的任意对象的实例方法的引用
请看下面的例子:
 
    
String[] stringArray = { "Barbara", "James", "Mary", "John",
"Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
与该方法引用String::compareToIgnoreCase等价的Lambda表达式拥有形式参数列表(String a, String b),其中a和b可以是任意有意义的名字。该方法引用实际调用了方法a.compareToIgnoreCase(b)。

构造方法的引用
引用构造方法只需要将静态方法引用中的方法名替换为new即可。下面的方法将元素从一个集合复制到另一集合。
 
    
public static <T, SOURCE extends Collection<T>, DEST extends Collection<T>>
DEST transferElements(
SOURCE sourceCollection,
Supplier<DEST> collectionFactory) {
DEST result = collectionFactory.get();
for (T t : sourceCollection) {
result.add(t);
}
return result;
}
函数接口Supplier包含了一个get方法,不接收参数并返回一个对象。因而,你可以使用lambda表达式调用transferElements方法:
 
    
Set<Person> rosterSetLambda =
transferElements(roster, () -> { return new HashSet<>(); });
进一步的,该lambda表达式可以使用构造函数引用替换:
 
    
Set<Person> rosterSet = transferElements(roster, HashSet::new);
Java编译器推导出你需要创建一个包含Person元素的HashSet,因而你可以更明确的指定:
 
    
Set<Person> rosterSet = transferElements(roster, HashSet<Person>::new);

你可能感兴趣的:(编程语言)