对于java lambda method reference, 我也只是略知一二

core-java
标签: #<Tag:0x00007f1d25ab7888>

#1

语法

Method reference有四种用法

1. 使用类名指定一个静态方法 (Class::static_method)

cars.sort(Car::compareByYear);

2. 使用类名指定一个非静态方法 (Class::method)

cars.sort(Car::compareByYear3);
cars.forEach(Car::toString2);

3. 使用实例名指定一个非静态方法 (instance::method)

cars.sort(car::compareByYear2);

4. 使用类名指定构造器方法 (Class::new)

Car car5 = Car.create(Car::new);

这个是 Car class

public class Car {
    private String name;
    private int year;

    public Car () {

    }

    public Car (String name, int year) {
        this.name = name;
        this.year = year;
    }

    public static int compareByYear(Car car1, Car car2){
        return car1.getYear() > car1.getYear() ? 1 : -1;
    }

    public int compareByYear2(Car car1, Car car2){
        return car1.getYear() > car1.getYear() ? 1 : -1;
    }

    public int compareByYear3(Car car){
        return this.year > car.getYear() ? 1 : -1;
    }

    public static Car create (final Supplier<Car> carSupplier) {
        return carSupplier.get();
    }

    public String toString2() {
        return name;
    }

    public int getYear() {
        return year;
    }

}
public class MethodReference {
    public static void main(String[] args) {

        List<Car> cars = Arrays.asList(new Car("car1", 2001),
                new Car("car2", 2002),
                new Car("car3", 2003),
                new Car("car4", 2004));
        
        Car car = new Car("car", 2019);

        cars.sort((car1, car2) -> car1.getYear() > car2.getYear() ? 1 : -1);

        cars.sort(Car::compareByYear);

        cars.sort(car::compareByYear2);

        cars.sort(Car::compareByYear3);
        cars.forEach(Car::toString2);

        Car car5 = Car.create(Car::new);

        cars.forEach(System.out::println);
    }
}

这个语法对于 java 来说是有点奇怪, 但是熟悉 javascript 的同学应该会很亲切吧, 在 javascript 里可以把方法当做参数或变量传来传去. 我觉得这里也可以这样理解, 比如

cars.sort(Car::compareByYear);

我们也可以写成这样

cars.sort((car1, car2) -> car1.getYear() > car2.getYear() ? 1 : -1);

这里使用 Lambda 表达式. sort() 方法接收一个Comparator参数, Comparator 是函数接口, 需要实现compare()方法, 而

(car1, car2) -> car1.getYear() > car2.getYear() ? 1 : -1

其实就是compare()方法的具体实现, 其实是写一个方法实现, 然后传进 sort()方法里.那么这种写法

cars.sort(Car::compareByYear);

就可以理解为 把方法体写在另外一个方法(compareByYear())里, 然后把这个方法传进 sort()里, 而两个冒号前的 Car 只是为了说明这个方法在什么地方.
不知道这样解释大家有没有明白.

所以需要传进什么方法, 首先要看方法接收什么方法, 比如List 的 forEach 方法, 他接收一个Consumer

default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}

而 Consumer接口需要实现accept 方法

void accept(T t);

所以, 这里只要一个方法是接收 Car 对象, 并且没有返回值, 那么这个方法就可以传进 forEach(), 比如
上边的例子, 就把 toString2()传进了 forEach

public String toString2() {
    return name;
}

同理, list 的 sort 方法接受一个Comparator, 而Comparator接口需要实现compare方法

int compare(T o1, T o2);

所以只要有个方法接受 (Car, Car) 这种格式的参数, 并且返回 int, 就能传进 sort().
所以, 这个方法就可以被传进 sort() 方法

public static int compareByYear(Car car1, Car car2){
    return car1.getYear() > car1.getYear() ? 1 : -1;
}

上边列出的四种方法, 对于Class::static_method, instance::method, Class::new这三个应该比较好理解, 但是Class::method就有点奇怪了, 类名只能调用静态方法, 这里为什么能调用非静态方法呢? 其实这里不是调用, 类名只是说明方法在什么地方. 其实真正调用方法的还是一个实例, 比如这个例子.

public int compareByYear3(Car car){
    return this.year > car.getYear() ? 1 : -1;
}
cars.sort(Car::compareByYear3);

虽然 sort 方法需要一个这样的方法

int compare(T o1, T o2);

但是这个方法也可以传进去

int compareByYear3(Car car)

这里java 在编译时具体做了什么我不太清楚. 不过, 我们可以简单的把它理解成, 是一个 Car 的实例去调用compareByYear3这个方法.

关于 Lambda 我们最近也在学习. 以后会为大家带来更多我对 Lambda 的理解.