Method References
您使用lambda expressions创建匿名方法。但是,有时 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);
}}
假设您的社交网络应用程序的成员包含在一个数组中,并且您想按年龄对数组进行排序。您可以使用以下代码(在示例MethodReferencesTest中找到本节中描述的代码摘录):
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)
请注意,interfaceComparator
是功能interface。因此,您可以使用 lambda 表达式来代替定义然后创建实现Comparator
的类的新实例:
Arrays.sort(rosterAsArray,
(Person a, Person b) -> {
return a.getBirthday().compareTo(b.getBirthday());
}
);
但是,这种用于比较两个Person
实例的出生日期的方法已经存在Person.compareByAge
。您可以改为在 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)
相同。每个都有以下 Feature:
-
它的形式参数列表是从
Comparator<Person>.compare
复制的,即(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
。 JRE 推断方法类型参数,在这种情况下为(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;
}
功能interfaceSupplier
包含一个方法get
,该方法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);