【从零单排】浅析Java 8新特性Method Reference

什么是方法引用

我们知道了什么是Lambda Expression以及如何使用,那么,Method References又是什么呢?Oracle Java Docs中这样说:

They are compact, easy-to-read lambda expressions for methods that already have a name.

也就是说,它是把已经定义好的有名字的方法,当作Lambda Expression来使用。

它的常用语法为:className::methodName

理解方法引用

通过一个例子来看:有一个数组,里面放了一堆Person对象,现在想要对它根据生日进行排序。

Person类

public class Person {
    LocalDate birthday;
    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()]);

class PersonAgeComparator implements Comparator<Person> {
    public int compare(Person a, Person b) {
        return a.getBirthday().compareTo(b.getBirthday());
    }
}

Arrays.sort(rosterAsArray, new PersonAgeComparator());

Lambda Expression写法1:手动比较两个Date

Arrays.sort(rosterAsArray,
    (Person a, Person b) -> {
        return a.getBirthday().compareTo(b.getBirthday());
    }
);

分析这个Lambda Expression

  • 首先,它overwrite了Comparator.compare()方法。
  • 然后,看一下compare()的参数:int compare(T o1, T o2),它的输入是两个类型一致的对象,返回值为int型。对应到表达式:
  • 左边:(Person a, Person b),定义了输入参数,两个Person类型的对象。
  • 右边:a.getBirthday().compareTo(b.getBirthday()),定义了输出参数,类型为int。

我们发现,对于右边,不一定要调用Date.compareTo()方法,其他任意自定义的方法都可以,只需要满足输入输出参数一致即可。

正好,Person类里面已经定义了一个compareByAge()方法可以直接拿过来替换。于是,可以改成这样:

Lambda Expression写法2:调用已经定义好的方法

Arrays.sort(rosterAsArray,
    (Person a, Person b) -> {
        return Person.compareByAge(a, b);
    }
);

再对其分析,可以发现,左边(Person a, Person b)其实是冗余信息,因为右边Person.compareByAge(a, b)方法已经定义好了输入输出。

所以,上面的代码可以简化如下:

Method Reference写法

Arrays.sort(rosterAsArray, Person::compareByAge);

几种类型

Method Reference有以下几种类型:

  • 引用静态方法: ClassName::staticMethodName
  • 引用构造方法: ClassName::new
  • 引用某个实例上的实例方法应用: instanceReference::instanceMethodName
  • 引用某个类型上的实例方法引用: ClassName::instanceMethodName

在使用“某个类型上的实例方法引用”时,需要传入实例化参数;而在使用“某个实例上的实例方法应用”时,因为已经实例化过了所以并不需要。

链接