Optional vs “if null”

Lately I see a lot of code like

Optional.ofNullable(i).orElse(x->doBla(x));

instead of a old known:

if (i != null) {
  doBla(i);
} 

It is debatable which style is easier to read. Especially when multiple layers are nested. It’s probably a matter of preference which style works better for you personally.

But what we can measure is the performance impact. Or since I do not have thus much time today let’s just quickly guess it.

Comparing the Source

The IF variant first:

NullFoo.java

public class NullFoo {
  public void test() {
    Integer i = 47;
    if (i != null ) {
      doSomething(i);
    }
  }

  private void doSomething(Integer i) {
    // actually we do nothing
  };
}

and now the functional version:

OptionalFoo.java


import java.util.Optional;

public class OptionalFoo {
  public void test() {
    Integer i = 47;
    Optional.ofNullable(i).ifPresent(x -> doSomething(x));
  }

  private void doSomething(Integer i) {
    // actually we do nothing
  };
}

The ByteCode

Judge about the performance yourself.
First the old style code as javap -c shows you:

~/tmp/delete/optionalfoo$>javap -c NullFoo.class
Compiled from "NullFoo.java"
public class NullFoo {
  public NullFoo();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return

  public void test();
    Code:
       0: bipush        47
       2: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       5: astore_1
       6: aload_1
       7: ifnull        15
      10: aload_0
      11: aload_1
      12: invokespecial #3                  // Method doSomething:(Ljava/lang/Integer;)V
      15: return
}

The important part is line 7: ifnull. This is a dog cheap operation. Any modern cpu can execute 2 or 4 such CJMPZ (compare and jump if zero) operations per clock cycle and core (especially if the target fits into the jump prediction cache).

Now let’s look at the functional style Java bytecode:

~/tmp/delete/optionalfoo$>javap -c OptionalFoo.class
Compiled from "OptionalFoo.java"
public class OptionalFoo {
  public OptionalFoo();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return

  public void test();
    Code:
       0: bipush        47
       2: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       5: astore_1
       6: aload_1
       7: invokestatic  #3                  // Method java/util/Optional.ofNullable:(Ljava/lang/Object;)Ljava/util/Optional;
      10: aload_0
      11: invokedynamic #4,  0              // InvokeDynamic #0:accept:(LOptionalFoo;)Ljava/util/function/Consumer;
      16: invokevirtual #5                  // Method java/util/Optional.ifPresent:(Ljava/util/function/Consumer;)V
      19: return
}

First we see a construtor invocation for Optional via invokestatic in line 2 followed by a push of the this pointer (aload_0).
Line 11 is a pretty expensive invokedynamic operation. It used to be way worse but even in the Java8 JVM invokedynamic is considerably more expensive than invokevirtual (simple method call).
And of course the call to the ifPresent method from our own code itself as well.

Note that there is a lot more going on in the following code parts (at least to a CJMPZ):

  • Code inside the Optional constructor
  • Code inside ifPresent

Fazit

Of course, if you do not invoke the code parts a million times per second then it probably will not matter. In which case you should use the style which is more readable (I personally still prefer the old null check).

But if you have to perform serious heavy lifting, then I suggest you benchmark your code with JMH. And you will most probably end up with the classic if statement. The code using a old-school nullcheck is about 200 times faster than the Optional variant.

Advertisements

About struberg
I'm an Apache Software Foundation member blogging about Java, µC, TheASF, OpenWebBeans, Maven, MyFaces, CODI, GIT, OpenJPA, TomEE, DeltaSpike, ...

5 Responses to Optional vs “if null”

  1. Hi,

    Reasoning on Byte Code for performance is really wrong. I suggest you to look at the generated code by the JIT and you will see that in both cases the generated code is the same.

    Regards.

  2. Benjamin says:

    Brilliant. We should not be blinded by a new way of doing things but think about it.
    Sometimes old-fashioned is still the way to go…
    Thanks

    • struberg says:

      Hi Benjamin!

      Txs for the feedback.
      But not quite sure if my fazit came across correctly: There are some cases where Optional is better to read than the old null checks. And if you have this in some business code doing remote calls or DB access, then that tiny bit of performance doesn’t matter.

      But if you do it in a loop where you need high performance then it might make a difference.

      All in all I think the whole Optional in Java is a missed opportunity.
      If you look at Swift or Kotlin then you might see what I mean.
      They introduced optional types, e.g.
      var bello: Dog? -> bello is optional and can be ‘null’, vs
      var bello: Dog = new Dog(“bello”) -> without the question mark a variable cannot be null, the compiler will detect this at build time.

      The same difference (? or not) exists for return values.

      Without telling the compiler the intention he simply cannot tell if the missing assignment is a human error or intentionally. This is a little bit like the ‘pure’ function classifier in Haskell to tell the compiler that a function is side-effect free.
      Another missed opportunity…

      LieGrue,
      strub

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: