java8 Lambda 详解

103 阅读4分钟

Lambda 某些匿名内部类的简化

方法引用

总结: 你的引用方法的参数个数、类型,返回值类型要和函数式接口中的方法声明一一对应才行 (函数接口的简写)

形式:

  • 对象::实例方法
  • 类::静态方法
  • 类::实例方法

image.png

image.png 静态方法引用: 如果我们在重写的时候,方法体中只有一行代码,并且这行代码是调用了某个类的静态方法,并且我们把要重写的抽象方法中所有的参数都按照顺序传入这个静态方法中,这个时候我们就可以引用类的静态方法

类的实例方法 如果我们在重写的时候,方法体中只有一行代码,并且这行代码是调用了第一个参数的成员方法,并且我们把要重写的抽象方法中剩余的所有的参数都按照顺序传入这个成员方法中,这个时候我们就可以引用类的成员方法
demo: 第一个参数是对象,其他和方法参数一致

@Data
public class Student {
    private String name;

    public Student(String name) {
        this.name = name;
    }
    public void hello(String hisName){
        System.out.printf("hello %s my Name is %s %n", hisName, name);
    }

    public static void main(String[] args) {
        KeyValueStreamingChannel<Student, String> hello = Student::hello;
        hello.onKeyValue(new Student("world"), "lili");
    }
}

对象实例方法: 如果我们在重写的时候,方法体中只有一行代码,并且这行代码是调用了某个类的成员方法,并且我们把要重写的抽象方法中所有的参数都按照顺序传入这个成员方法中,这个时候我们就可以引用对象的实例方法

构造器引用:

ClassName::new

方法引用的出现,使得我们可以将一个方法赋给一个变量或者作为参数传递给另外一个方法。::双冒号作为方法引用的符号,比如下面这两行语句,引用 Integer类的 parseInt方法。

Function<String, Integer> s = Integer::parseInt;
Integer i = s.apply("10");

和这个函数方法对应 :java.util.function.Function#apply R apply(T t);

Q:什么样的方法可以被引用?

A:这么说吧,任何你有办法访问到的方法都可以被引用。

Q:返回值到底是什么类型?

A:这就问到点儿上了,上面又是 Function、又是Comparator、又是 IntBinaryOperator的,看上去好像没有规律,其实不然。

返回的类型是 Java 8 专门定义的函数式接口,这类接口用 @FunctionalInterface 注解。

比如 Function这个函数式接口的定义如下:

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

还有很关键的一点,你的引用方法的参数个数、类型,返回值类型要和函数式接口中的方法声明一一对应才行。

比如 Integer.parseInt方法定义如下:

public static int parseInt(String s) throws NumberFormatException {
    return parseInt(s,10);
}

首先parseInt方法的参数个数是 1 个,而 Function中的 apply方法参数个数也是 1 个,参数个数对应上了,再来,apply方法的参数类型和返回类型是泛型类型,所以肯定能和 parseInt方法对应上。

这样一来,就可以正确的接收Integer::parseInt的方法引用,并可以调用Funcitonapply方法,这时候,调用到的其实就是对应的 Integer.parseInt方法了。

用这套标准套到 Integer::compare方法上,就不难理解为什么即可以用 Comparator<Integer>接收,又可以用 IntBinaryOperator接收了,而且调用它们各自的方法都能正确的返回结果。

Integer.compare方法定义如下:

public static int compare(int x, int y) {
    return (x < y) ? -1 : ((x == y) ? 0 : 1);
}

返回值类型 int,两个参数,并且参数类型都是 int

然后来看ComparatorIntBinaryOperator它们两个的函数式接口定义和其中对应的方法:

@FunctionalInterface
public interface Comparator<T> {
    int compare(T o1, T o2);
}
​
@FunctionalInterface
public interface IntBinaryOperator {
    int applyAsInt(int left, int right);
}

对不对,都能正确的匹配上,所以前面示例中用这两个函数式接口都能正常接收。其实不止这两个,只要是在某个函数式接口中声明了这样的方法:两个参数,参数类型是 int或者泛型,并且返回值是 int或者泛型的,都可以完美接收。

JDK 中定义了很多函数式接口,主要在 java.util.function包下,还有 java.util.Comparator 专门用作定制比较器。另外,前面说的 Runnable也是一个函数式接口。

参考:方法引用