Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
332 views
in Technique[技术] by (71.8m points)

java - Is there any difference between Objects::nonNull and x -> x != null?

Consider the following class:

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;
    }
}

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).

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?

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.)

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

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.

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.

Consider these small classes:

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

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

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

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.

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.

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...