Objects :: nonNull和x - >之间有什么区别吗? x!= null? [英] Is there any difference between Objects::nonNull and x -> x != null?

查看:183
本文介绍了Objects :: nonNull和x - >之间有什么区别吗? x!= null?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下类:

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短两个字符(可能允许流管道适合一行)。

The first predicate is created from a method reference and the other a lambda expression. These predicates have the same behavior (nonNull's body is just return obj != null;). The lambda is two characters shorter (perhaps allowing a stream pipeline to fit on one line).

除了代码样式, <$ c之间有什么区别$ c> Objects :: nonNull 和 x - > x!= null ?换句话说,我应该更喜欢一个吗?

Other than code style, is there any difference between Objects::nonNull and x -> x != null? Put another way, should I prefer one over the other?

lambda-dev和lambda-libs-spec- {observers,experts}邮件列表消息提到 isNull nonNull isNotNull (早期名称)没有解决这一点。 (我很惊讶没有人质疑添加Objects方法,因为它们可以用lambda轻易替换,但另一方面, Integer :: sum 也是如此。)

The lambda-dev and lambda-libs-spec-{observers,experts} mailing list messages mentioning isNull, nonNull and isNotNull (early name) didn't address this point. (I'm surprised no one questioned adding the Objects methods as they are trivially replaceable with a lambda, but on the other hand, so is Integer::sum.)

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

I also looked at the bytecode with javap. The only difference was the method handle passed to the 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

当然,metafactory可以为方法做不同的事情引用和lambdas,在JVM的一时兴起,所以证明不多。

Of course, the metafactory could do different things for method references and lambdas, at the whim of the JVM, so that doesn't prove much.

推荐答案

如你所述,语义lambda x - > x!= null 和方法引用 Objects :: nonNull 几乎完全相同。我很难想到任何实际可观察​​到的差异,没有使用反射进入课堂,或类似的东西。

As you noted, the semantics of the lambda x -> x != null and the method reference Objects::nonNull are virtually identical. I'm hard-pressed to think of any actual observable difference, short of digging into the class using reflection, or something like that.

有一个很小的空间优势使用lambda上的方法引用。使用lambda,lambda的代码被编译成包含类的私有静态方法,然后通过引用此静态方法调用lambda metafactory。在方法引用案例中,该方法已经存在于 java.util.Objects 类中,因此通过对现有方法的引用来调用lambda metafactory。这样可以节省适度的空间。

There is a small space advantage to using the method reference over the lambda. With the lambda, the code of the lambda is compiled into a private static method of the containing class, and the lambda metafactory is then called with a reference to this static method. In the method reference case, the method already exists in the java.util.Objects class, so the lambda metafactory is call with a reference to the existing method. This results in a moderate space savings.

考虑这些小班:

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> ,用于查看这些编译方式之间的详细差异。)

(Interested readers should run javap -private -cp classes -c -v <class> to view detailed differences between the way these are compiled.)

这导致1,094字节lambda case和989字节的方法参考案例。 (Javac 1.8.0_11。)这不是一个巨大的区别,但是如果你的程序可能有大量像这样的lambdas,你可以考虑使用方法引用节省空间。

This results in 1,094 bytes for the lambda case and 989 bytes for the method reference case. (Javac 1.8.0_11.) This isn't a huge difference, but if your programs are likely to have large numbers of lambdas like this, you might consider the space savings resulting from using method references.

此外,方法引用更有可能是jit编译和内联而不是lambda,因为方法引用可能使用得更多。这可能会导致性能微小改善。但是,这似乎不太可能产生实际的区别。

In addition, it is more likely that a method reference could be JIT-compiled and inlined than the lambda, since the method reference is probably used a lot more. This might result in a tiny performance improvement. It seems unlikely this would make a practical difference, though.

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

Although you specifically said "Other than code style..." this really is mostly about style. These small methods were specifically added to the APIs so that programmers could use names instead of inline lambdas. This often improves the understandability of the code. Another point is that a method reference often has explicit type information that can help out in difficult type inference cases, such as nested Comparators. (This doesn't really apply to Objects::nonNull though.) Adding a cast or explicitly-typed lambda parameters adds a lot of clutter, so in these cases, method references are a clear win.

这篇关于Objects :: nonNull和x - &gt;之间有什么区别吗? x!= null?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆