方法引用
你可以使用lambda表达式来创建匿名方法。 但是,有时,lambda表达式只是仅仅调用一个方法。在这些情况下,通过方法名称调用现有方法会更清楚得表达意思。java8得方法引用现在允许你这样做,对于已有名称的方法,方法引用是紧凑的,易于阅读的lambda表达式。
在Lambda 表达式中,我们创建了一个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得数组,你希望通过年龄Age来排序,代码请参考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)
我们发现Comparator
一个 functional interface接口,因此,我们应该使用lambda表达式,而不是定义然后创建实现Comparator的接口的新实例。
Arrays.sort(rosterAsArray,
(Person a, Person b) -> {
return a.getBirthday().compareTo(b.getBirthday());
}
);
但是,这种比较两个Person实例的birthday的方法,我们已经在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)
相同.
方法引用得种类
方法引用主要有四类。
种类 | 格式 | 例子 |
---|---|---|
指向静态方法得方法引用 | ContainingClass::staticMethodName | Integer::parseInt |
指向任意类型实例方法得方法引用 | ContainingType::methodName | String::length |
指向现有对象的实例方法得方法引用 | containingObject::instanceMethodName | person::getEmailAddress |
指向构造函数 | ClassName::new | Person::new |
指向静态方法得方法引用
方法引用 Person :: compareByAge
就是对静态方法的引用。
指向任意类型实例方法得方法引用
引用示例:
String[] stringArray = { "Barbara", "James", "Mary", "John",
"Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
方法引用 String::compareToIgnoreCase
等效的lambda表示式为:
(String a,String b)-> a.compareToIgnoreCase(b)
Arrays.sort(stringArray, (a, b) -> {
return Person.compareByAge(a, b);
});
指向现有对象的实例方法得方法引用
引用示例:
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)。
指向构造函数
引用示例:
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;
}
functional interface 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);
网友评论