上一节介绍了 Java8 新特性中的 Lambda 表达式, 本小节继续讲解 Java8 的新特性之二: 方法引用. 方法引用其实也离不开 Lambda 表达式.
1, 方法引用的使用场景
我们用 Lambda 表达式来实现匿名方法. 但有些情况下, 我们用 Lambda 表达式仅仅是调用一些已经存在的方法, 除了调用动作外, 没有其他任何多余的动作, 在这种情况下, 我们倾向于通过方法名来调用它, 而 Lambda 表达式可以帮助我们实现这一要求, 它使得 Lambda 在调用那些已经拥有方法名的方法的代码更简洁, 更容易理解. 方法引用可以理解为 Lambda 表达式的另外一种表现形式.
2, 方法引用的分类
语法 | 对应的 Lambda 表达式 | |
---|---|---|
静态方法引用 | 类名::staticMethod | (args) -> 类名. staticMethod(args) |
实例方法引用 | inst::instMethod | (args) -> inst.instMethod(args) |
对象方法引用 | 类名::instMethod | (inst,args) -> 类名. instMethod(args) |
构建方法引用 | 类名::new | (args) -> new 类名(args) |
3, 方法引用举例
3.1 静态方法引用
有一个 Person 类, 如下所示:
- @Data
- public class Person {
- private String name;
- private Integer age;
- public static int compareByAge(Person a, Person b) {
- return a.age.compareTo(b.age);
- }
- }
现假设, 一个部门有 30 人, 把他们存放在一个数组中, 并按年龄排序, 通常我们可以自己写一个比较器, 代码如下:
- Person[] rosterAsArray = new Person[30];
- // 添加数组元素省略
- class PersonAgeComparator implements Comparator<Person> {
- public int compare(Person a, Person b) {
- return a.getBirthday().compareTo(b.getBirthday());
- }
- }
- Arrays.sort(rosterAsArray, new PersonAgeComparator());
Arrays.sort 的声明为: public static <T> void sort(T[] a, Comparator<? super T> c), 比较器参数 Comparator 为一个函数式接口, 利用上一节 Lambda 表达式所学知识, 可以改写为以下代码:
- Person[] rosterAsArray = new Person[30];
- // 添加数组元素省略
- Arrays.sort(rosterAsArray, (a,b) -> a.getAge().compareTo(b.getAge()));
然而, 你会发现, Perdon 类中已经有了一个静态方法的比较器: compareByAge, 因此, 我们改用 Person 类已经提供的比较器:
- Person[] rosterAsArray = new Person[30];
- // 添加数组元素省略
- Arrays.sort(rosterAsArray, (a,b) -> Person.compareByAge(a,b));
以上代码, 因为 Lambda 表达式调用了一个已经存在的静态方法, 根据我们第 2 节表格中的语法, 上面的代码可以最终改写成静态方法引用:
- Person[] rosterAsArray = new Person[30];
- // 添加数组元素省略
- Arrays.sort(rosterAsArray, Person::compareByAge);
下面这个例子更简单:
- public class Test {
- public static void main(String[] args) {
- List<Integer> list = Arrays.asList(82,22,34,50,9);
- list.sort(Integer::compare);
- System.out.println(list);
- }
- }
对一个 Integer 列表进行排序, 因为 Integer 中已经存在静态的比较方法 compare(), 因此可以直接用静态方法引用的方式来调用 , 运行结果为:
[9, 22, 34, 50, 82]
3.2 实例方法引用
实例方法引用, 顾名思义就是调用已经存在的实例的方法, 与静态方法引用不同的是类要先实例化, 静态方法引用类无需实例化, 直接用类名去调用.
- @Data
- class User {
- private String name;
- private Integer age;
- public User(String name, Integer age) {
- this.name = name;
- this.age = age;
- }
- }
- public class TestInstanceReference {
- public static void main(String[] args) {
- TestInstanceReference test = new TestInstanceReference();
- User user = new User("欧阳峰",32);
- Supplier<String> supplier = () -> user.getName();
- System.out.println("Lambda 表达式输出结果:" + supplier.get());
- Supplier<String> supplier2 = user::getName;
- System.out.println("实例方法引用输出结果:" + supplier2.get());
- }
- }
输出结果:
Lambda 表达式输出结果: 欧阳峰
实例方法引用输出结果: 欧阳峰
3.3 对象方法引用
若 Lambda 参数列表中的第一个参数是实例方法的参数调用者, 而第二个参数是实例方法的参数时, 可以使用对象方法引用.
String 的 equals() 方法:
- public boolean equals(Object anObject) {
- if (this == anObject) {
- return true;
- }
- if (anObject instanceof String) {
- String anotherString = (String)anObject;
- int n = value.length;
- if (n == anotherString.value.length) {
- char v1[] = value;
- char v2[] = anotherString.value;
- int i = 0;
- while (n-- != 0) {
- if (v1[i] != v2[i])
- return false;
- i++;
- }
- return true;
- }
- }
- return false;
- }
- public static void main(String[] args) {
- BiPredicate<String,String> bp = (x, y) -> x.equals(y);
- BiPredicate<String,String> bp1 = String::equals;
- boolean test = bp1.test("xy", "xx");
- System.out.println(test);
- }
BiPredicate 的 test() 方法接受两个参数, x 和 y, 具体实现为 x.equals(y), 满足 Lambda 参数列表中的第一个参数是实例方法的参数调用者, 而第二个参数是实例方法的参数, 因此可以使用对象方法引用.
3.4 构造方法引用
注意: 需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致.
如: 要获取一个空的 User 列表:
- Supplier<List<User>> userSupplier = () -> new ArrayList<>();
- List<User> user = userSupplier.get();
- Supplier<List<User>> userSupplier2 = ArrayList<User>::new; // 构造方法引用写法
- List<User> user2 = userSupplier.get();
至此, 方法引用讲完了, 下一章节将讲解 Stream API.
来源: https://www.cnblogs.com/wuhenzhidu/p/10727065.html