Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 553
Jeffrey Bosboom Avatar asked Aug 21 '14 20:08

Jeffrey Bosboom


People also ask

What is Objects :: nonNull?

The nonNull method is a static method of the Objects class in Java that checks whether the input object reference supplied to it is non-null or not. If the passed object is non-null, then the method returns true. If the passed object is null , then the method returns false.

How do you check if an object is null?

To check if it is null, we call the isNull() method and pass the object getUserObject as a parameter. It returns true as the passed object is null.

Is it good to use Objects requireNonNull?

requireNonNull(bar, "bar must not be null"); is ok in constructors, but potentially dangerous in other methods if two or more variables are set in the same method.

What is Objects isNull?

Overview. The method isNull is a static method of the Objects class in java that checks whether the input object reference supplied to it is null or not. If the passed object is null , then the method returns true . If the passed object is non-null , then the method returns false .


1 Answers

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.

like image 94
Stuart Marks Avatar answered Sep 19 '22 03:09

Stuart Marks