Java Lambda表达式与方法引用实现详细信息

Java Lambda表达式与方法引用实现详细信息,java,lambda,Java,Lambda,鉴于此: class MyClass { static class A { public boolean property() { return Math.random() < 0.5; } } static List<A> filterLambda(List<A> list) { return list.stream().filter(a -> a.proper

鉴于此:

class MyClass {
    static class A {
        public boolean property() {
            return Math.random() < 0.5;
        }
    }

    static List<A> filterLambda(List<A> list) {
        return list.stream().filter(a -> a.property()).collect(Collectors.toList());
    }

    static List<A> filterMethodCall(List<A> list) {
        return list.stream().filter(A::property).collect(Collectors.toList());
    }
}
class-MyClass{
静态A类{
公共布尔属性(){
返回Math.random()<0.5;
}
}
静态列表,但我认为它没有被正确处理。

是方法引用的java语言规范

是lambda表达式的规范

从规则的角度来看,lambda要复杂得多

但是,在这两种情况下,结果都是invokedynamic调用


Brian Goetz写了一篇关于这是如何工作的文章。

这是Brett Oken链接文章的摘录:

当编译器遇到lambda表达式时,它首先降低 (desugars)将lambda体转换为一个方法,该方法的参数列表和 返回类型与lambda表达式的返回类型匹配,可能与 附加参数(用于从词法范围捕获的值,如果需要) 在捕获lambda表达式的点, 它生成一个invokedynamic调用站点,调用该站点时返回 lambda正在连接到的功能接口的实例 已转换。此调用站点称为给定对象的lambda工厂 lambda工厂的动态参数是值 从词法范围捕获。lambda的引导方法 factory是Java语言运行库中的标准化方法, 称为lambda元工厂。静态引导参数捕获 编译时关于lambda的已知信息(函数 接口,该接口是 脱糖lambda body,有关SAM类型是否正确的信息 可序列化等)

方法引用的处理方式与lambda表达式相同, 除了大多数方法引用不需要被分解成 新方法;我们只需为 引用的方法并将其传递给元工厂

从同一文档中提取的示例:

作为一个例子,考虑一个捕获字段MIXSIG:

的lambda。
list.filter(e -> e.getSize() < minSize )
翻译为:

list.filter(indy(MH(metaFactory), MH(invokeVirtual Predicate.apply),
             MH(invokeVirtual String.isEmpty))()))

我们可以找到lambda表达式和方法引用的差异的一个例子是作为供应商接口的一部分使用的

public static <T, E> T catchException(Supplier<T> resolver) {
    try {
        T result = resolver.get();
        return  result ;
    } catch (Exception e) {
        System.out.println("Exception");
        return null;
    }
}
公共静态捕获异常(供应商解析程序){
试一试{
T result=resolver.get();
返回结果;
}捕获(例外e){
System.out.println(“例外”);
返回null;
}
}
当我们像下面那样使用lambda表达式调用该方法时,代码工作正常,因为lambda表达式作为Supplier的一部分传递&只有在捕获异常的地方调用get()方法时才会执行

List<String> underlyers=null;
System.out.println(catchException(()->underlyers.size()));
List underyers=null;
System.out.println(catchException(()->underlayers.size());
当我们使用下面的方法引用调用该方法时,我们会在调用该方法之前获取NullPointerExecOption,因为该引用是在传递给供应商之前执行的。在这种情况下,控件不会到达get()方法

List<String> underlyers=null;
System.out.println(catchException(underlyers::size));
List underyers=null;
System.out.println(catchException(underyers::size));

我不是问应该使用哪一个,而是感谢“编译器的功能”链接可能超出了这里的回答范围。规范提供了一些理论背景信息,但不清楚您希望深入了解实际编译器实现的程度。我可以肯定的是,为这两种方法生成的字节码是相同的。
List<String> underlyers=null;
System.out.println(catchException(()->underlyers.size()));
List<String> underlyers=null;
System.out.println(catchException(underlyers::size));