方法引用(Method Reference)
上一篇中记录了Lambda表达式,其可以创建匿名方法。当Lambda表达式只是调用一个存在的方法时,可以采用方法引用(JDK8具有的特性)。如下:
1 public class Person { 2 3 public enum Sex { 4 MALE, FEMALE 5 } 6 7 String name; 8 LocalDate birthday; 9 Sex gender; 10 String emailAddress; 11 int age; 12 13 public int getAge() { 14 return age; 15 } 16 17 public LocalDate getBirthday() { 18 return birthday; 19 } 20 21 public static int compareByAge(Person a, Person b) { 22 return a.birthday.compareTo(b.birthday); 23 } 24 }
假设需要对一组人员按年龄进行排序,可以采用下边的方式,将人员数组与实现的比较器,传递给Array.sort方法:
1 Person[] rosterAsArray = roster.toArray(new Person[roster.size()]); 2 3 class PersonAgeComparator implements Comparator<Person> { 4 public int compare(Person a, Person b) { 5 return a.getBirthday().compareTo(b.getBirthday()); 6 } 7 } 8 9 Arrays.sort(rosterAsArray, new PersonAgeComparator());
当然,可以将PersonAgeComparator的实现采用Lambda表达式,如下:
1 Arrays.sort(rosterAsArray, (a,b) -> a.birthday.compareTo(b.birthday));
Person类中已经包含根据年龄的比较compareByAge,只需要在Lambda表达式体中直接调用即可:
1 Arrays.sort( rosterAsArray, (a,b) -> Person.compareByAge(a,b));
由于Lambda表达式调用一个已经存在的方法,可以使用方法引用代替Lambda表达式,如下:
1 Arrays.sort(rosterAsArray, Person::compareByAge);
其中 ,Person::compareByAge 与 (a, b) -> Person.compareByAge(a, b)是等价的。(1)其参数拷贝于Comparator<Person>.compare,即 (Person, Person);(2)body将调用Person.compareByAge。
方法引用类别
有4种方法引用,如下:
- 引用静态方法,如 ContainingClass::staticMethodName;
- 引用实例方法,如 containingObject::instanceMethodName;
- 引用特殊类型对象的方法,如 ContainingType::methodName;
- 引用构造函数,如 ClassName::new。
(1)引用静态方法
上文中的例子即为静态方法引用。
(2)引用实例方法
即通过类的实例引用方法,如下:
1 class ComparisonProvider { 2 public int compareByName(Person a, Person b) { 3 return a.getName().compareTo(b.getName()); 4 } 5 6 public int compareByAge(Person a, Person b) { 7 return a.getBirthday().compareTo(b.getBirthday()); 8 } 9 } 10 ComparisonProvider myComparisonProvider = new ComparisonProvider(); 11 Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);
(3)引用特殊类型对象的方法
以String为例:
1 String[] stringArray = { "Barbara", "James", "Mary", "John", 2 "Patricia", "Robert", "Michael", "Linda" }; 3 Arrays.sort(stringArray, String::compareToIgnoreCase);
(4)引用构造函数
假设transferElements实现从一个集合到另一个集合拷贝元素,如下:
1 public static <T, SOURCE extends Collection<T>, DEST extends Collection<T>> 2 DEST transferElements( 3 SOURCE sourceCollection, 4 Supplier<DEST> collectionFactory) { 5 6 DEST result = collectionFactory.get(); 7 for (T t : sourceCollection) { 8 result.add(t); 9 } 10 return result; 11 }
其中Supplier包含一个get方法,只返回一个空的集合对象,并且不需要任何参数,可以使用Lambda表达式实现,如下:
1 Set<Person> rosterSetLambda = 2 transferElements(roster, () -> { return new HashSet<>(); });
此时可以采用引用构造函数的方法,如下:
Set<Person> rosterSet = transferElements(roster, HashSet::new); //或 Set<Person> rosterSet = transferElements(roster, HashSet<Person>::new);
总结
- 对于Lambda表达式,当只是调用一个已存在的方法时,可以采用方法引用的方式实现,编译器会自行翻译
参考