gpt4 book ai didi

java - Objects::nonNull 和 x -> x != null 之间有什么区别吗?

转载 作者:搜寻专家 更新时间:2023-10-30 20:59:38 24 4
gpt4 key购买 nike

考虑以下类:

import java.util.Objects;
import java.util.function.Predicate;

public class LambdaVsMethodRef {
public static void main(String[] args) {
Predicate<Object> a = Objects::nonNull;
Predicate<Object> b = x -> x != null;
}
}

第一个谓词是从方法引用创建的,另一个是 lambda 表达式。这些谓词具有相同的行为(nonNull 的主体只是 return obj != null;)。 lambda 短了两个字符(可能允许流管道适合一行)。

除了代码风格,Objects::nonNullx -> x != null 之间有什么区别吗?换句话说,我应该更喜欢其中一个吗?

lambda-dev 和 lambda-libs-spec-{observers,experts} 邮件列表消息提及 isNullnonNullisNotNull ( early name) 没有解决这一点。 (我很惊讶没有人质疑添加 Objects 方法,因为它们很容易被 lambda 替换,但另一方面,Integer::sum 也是如此。)

我还用 javap 查看了字节码。唯一的区别是传递给 lambda metafactory bootstrap method 的方法句柄。 :

  BootstrapMethods:
0: #16 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#17 (Ljava/lang/Object;)Z
#18 invokestatic java/util/Objects.nonNull:(Ljava/lang/Object;)Z
#17 (Ljava/lang/Object;)Z
1: #16 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#17 (Ljava/lang/Object;)Z
#20 invokestatic LambdaVsMethodRef.lambda$main$1:(Ljava/lang/Object;)Z
#17 (Ljava/lang/Object;)Z

当然,根据 JVM 的突发奇想,元工厂可以为方法引用和 lambda 做不同的事情,所以这并不能证明什么。

最佳答案

如您所述,lambda 的语义 x -> x != null和方法引用Objects::nonNull几乎相同。我很难想到任何实际可观察​​到的差异,除非使用反射或类似方法深入研究类。

在 lambda 上使用方法引用有一个小的空间优势。使用 lambda,lambda 的代码被编译成包含类的私有(private)静态方法,然后通过引用这个静态方法调用 lambda 元工厂。在方法引用案例中,该方法已经存在于java.util.Objects中类,因此调用 lambda 元工厂时会引用现有方法。这导致适度的空间节省。

考虑这些小类:

class LM { // lambda
static Predicate<Object> a = x -> x != null;
}

class MR { // method reference
static Predicate<Object> a = Objects::nonNull;
}

(有兴趣的读者应该运行 javap -private -cp classes -c -v <class> 来查看这些编译方式之间的详细差异。)

这导致 lambda 案例有 1,094 个字节,方法引用案例有 989 个字节。 (Javac 1.8.0_11。)这不是很大的区别,但如果您的程序可能有大量这样的 lambda,您可能会考虑使用方法引用节省的空间。

此外,与 lambda 相比,方法引用更有可能被 JIT 编译和内联,因为方法引用可能使用得更多。这可能会带来微小的性能提升。不过,这似乎不太可能产生实际影响。

虽然您特别说过“除了代码风格...”,但这实际上主要是关于风格。这些小方法专门添加到 API 中,以便程序员可以使用名称而不是内联 lambda。这通常会提高代码的可理解性。另一点是,方法引用通常具有显式类型信息,可以在困难的类型推断情况下提供帮助,例如嵌套比较器。 (虽然这并不真正适用于 Objects::nonNull。)添加强制转换或显式类型化的 lambda 参数会增加很多困惑,因此在这些情况下,方法引用是一个明显的胜利。

关于java - Objects::nonNull 和 x -> x != null 之间有什么区别吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25435056/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com