Lambda之方法的引用
Lambda创建一个匿名方法,这提供了一种比拥有一个方法的匿名类更简洁的用法。如果说Lambda简单到只需要调用一个现有的方法,那么方法引用可以作为一个Lambda表达式来让代码变的更加简洁直观。
方法是可以引用的
回顾初识Lambda当中介绍的场景,现在管理员需要用户按照生日进行排序,Lambda可以简洁直观的完成这个场景。
List<Person> roster = Person.createRoster();
Person[] rosterAsArray = roster.toArray(new Person[roster.size()]);
Arrays.sort(rosterAsArray,
(a, b) -> {
return a.getBirthday().compareTo(b.getBirthday());
}
);
由于Person
提供了一个静态方法compareByAge
,这个方法简化排序算法的代码。
Arrays.sort(rosterAsArray,
(a, b) -> {
return Person.compareByAge(a, b);
}
);
但这并不是最干净的方式,借助方法引用可以更加简单。
Arrays.sort(rosterAsArray,Person::compareByAge);
Person::compareByAge
完全等同于(a, b) -> { return Person.compareByAge(a, b); }
。
因为Lambda表达式仅仅使用到了一个简单的方法,所以可以借助方法引用这个特性直接将这个方法作为Lambda表达式使用。
哪类方法可以引用
类型 | 使用方式 |
---|---|
静态方法 | 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);
特定类实例的任意方法
这个用法与上面相比稍微特殊一些。
String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
可以看到sort
操作的对象是String
数组,compareToIgnoreCase
既不是静态方法,同时也没有通过使用一个String
对象的方法引用,而是直接将String
的compareToIgnoreCase
方法作为Lambda。compareToIgnoreCase
实际只有一个输入参数,Lambda的目标类型Compartor<T>
的compare(T o1, T o2)
是有两个输入参数的,按照之前的方式,这个引用的方法似乎也是需要两个String
类型的参数。
其实并非如此,虽然Lambda有两个输入参数,这两个输入参数可以看做是a
和b
,方法的引用则与a.compareToIgnoreCase(b)
这种调用方式相同。
构造方法
定义了一个可以转换集合实现方式的方法,这个方法可以将一种集合对象转换成另外一种集合对象。
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
是一个JDK标准函数接口,它提供了一个get
的无参方法,这里通过get
构造了一个Set实例。如果把一个List集合转换成Set集合,使用Lambda实现:
Set<Person> rosterSetLambda = transferElements(roster, () -> { return new HashSet<>(); });
通过构造方法的引用变的更简洁。
Set<Person> rosterSet = transferElements(roster, HashSet::new);
编译器可以推断出HashSet的类型参数,也可以显式声明类型参数。
Set<Person> rosterSet = transferElements(roster, HashSet<Person>::new);