方法引用的概念
某些lambda表达式里面仅仅是执行一个方法调用。在这种情况下,不用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[]rosterAsArray = roster.toArray(new Person[roster.size()]);//可认为roster是你好友的名册
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表达式,省去了定义PersonAgeComparator 类和创建一个类实例,如下。
Arrays.sort(rosterAsArray,
(Person a, Person b) -> {
return a.getBirthday().compareTo(b.getBirthday());
}
);
然而, 比较两个Person对象的生日大小的方法Person.compareByAge,已经在Person类中定义了。 这样,在lambda表达式主体内直接调用Person.compareByAge就好了:
Arrays.sort(rosterAsArray,
(a, b) -> Person.compareByAge(a, b)
);
因为上面的lamdba表达式调用了一个现成的方法,所以可以用方法引用替代这个lamdba表达式:
Arrays.sort(rosterAsArray,
Person::compareByAge
);
方法引用Person::compareByAge跟lambda表达式(a, b) -> Person.compareByAge(a,b)在语义上是等价的。 两者有如下的特征 :
· 形参相同 ,都是(Person, Person)。
· 调用方法Person.compareByAge。
方法引用的种类
一共有四种类型的方法引用:
类型 |
示例 |
类静态方法引用 |
ContainingClass::staticMethodName |
某个对象的方法引用 |
ContainingObject::instanceMethodName |
特定类的任意对象的方法引用 |
ContainingType::methodName |
构造方法引用 |
ClassName::new |
1)静态方法引用
方法引用Person::compareByAge 就是对一个静态方法引用。
2)某个对象的方法引用
下面就是一个对特定对象的实例方法引用的例子:
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)。
3)特定类的任意对象的方法引用
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) 方法执行。
4)构造方法引用
使用new关键词引用构造方法就像引用类静态方法一样。下面方法实现了从一个集合复制其元素到另一个集合中:
public static <T, SOURCE extends Collection<T>, DEST extends Collection<T>>
DEST transferElements(
SOURCEsourceCollection,
Supplier<DEST>collectionFactory) {
DESTresult = collectionFactory.get();
for (T t : sourceCollection) {
result.add(t);
}
return result;
}
函数接口Supplier有一个方法get,get无输入参数,输出是一个对象。这样,你可以使用一个lambda 表达式调用transferElements方法,如下所示:
Set<Person>rosterSetLambda =
transferElements(roster, () -> { return new HashSet<>(); });
进一步,你可以使用构造方法引用来替代lambda 表达式:
Set<Person>rosterSet = transferElements(roster, HashSet::new);
Java编译器推断出你想创建一个HashSet集合,其中包含Person类型的元素。当然,你也可以像下面这样显式的指定集合元素的类型为Person
Set<Person>rosterSet = transferElements(roster,HashSet<Person>::new);
http://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html