0%

Java Optional – orElse() vs orElseGet()

1. Introduction

The API of Optional typically has two methods that can cause confusion: orElse() and orElseGet().

In this quick tutorial, we’ll look at the difference between those two and explore when to use each one.

2. Signatures

Let’s first start with the basics by looking at their signatures:

1
2
3
public T orElse(T other)

public T orElseGet(Supplier<? extends T> other)

Clearly, orElse() takes any parameter of a type T whereas orElseGet() accepts a functional interface of type Supplier that returns an object of type T.

Now, based on their Javadocs:

  • orElse(): returns the value if present, otherwise return other
  • orElseGet(): returns the value if present, otherwise invoke other and return the result of its invocation

3. Differences

It’s easy to be a bit confused by this simplified definitions, so let’s dig a little deeper and look at some actual usage scenarios.

3.1. orElse()

Assuming we have our logger configured properly, let’s start with writing a simple piece of code:

1
2
String name = Optional.of("baeldung")
.orElse(getRandomName());

Notice that getRandomName() is a method which returns a random name from a *List*of names:

1
2
3
4
5
6
7
8
9
public String getRandomName() {
LOG.info("getRandomName() method - start");

Random random = new Random();
int index = random.nextInt(5);

LOG.info("getRandomName() method - end");
return names.get(index);
}

On executing our code, we’ll find below messages printed in the console:

1
2
getRandomName() method - start
getRandomName() method - end

The variable name will hold “baeldung” at the end of the code execution.

With it, we can easily infer that the parameter of *orElse()* is evaluated even when having a non-empty *Optional*.

3.2. orElseGet()

Now, let’s try writing similar code using orElseGet():

1
2
String name = Optional.of("baeldung")
.orElseGet(() -> getRandomName());

The above code will not invoke getRandomName() method.

Remember (from the Javadoc) that the S*upplier* method passed as an argument is only executed when *an Optional* value is not present.

Using orElseGet() for our case will, therefore, save us some time involved in computing a random name.

4. Measuring Performance Impact

Now, to also understand the differences in performance, let’s use JMH and see some actual numbers:

1
2
3
4
5
@Benchmark
@BenchmarkMode(Mode.AverageTime)
public String orElseBenchmark() {
return Optional.of("baeldung").orElse(getRandomName());
}

And orElseGet():

1
2
3
4
5
@Benchmark
@BenchmarkMode(Mode.AverageTime)
public String orElseGetBenchmark() {
return Optional.of("baeldung").orElseGet(() -> getRandomName());
}

While executing our benchmark methods, we get:

1
2
3
Benchmark           Mode  Cnt      Score       Error  Units
orElseBenchmark avgt 20 60934.425 ± 15115.599 ns/op
orElseGetBenchmark avgt 20 3.798 ± 0.030 ns/op

As we can see, the performance impact might be substantial even for such a simple use-case scenario.

The numbers above might slightly vary, however, *orElseGet()* has clearly outperformed *orElse()* for our particular example.

Afterall, orElse() involves computation of getRandomName() method for each run.

5. What’s Important?

Apart from the performance aspects, other worth-considering factors involve:

  • What if the method would execute some additional logic? E.g. making some DB inserts or updates

  • Even when we assign an object to

    orElse()

    parameter:

    1
    String name = Optional.of("baeldung").orElse("Other")

    we’re still creating “Other” object for no reason

And that’s why it is important for us to make a careful decision among orElse() and orElseGet() depending on our needs – by default, it makes more sense to use *orElseGet()* every time unless the default object is already constructed and accessible directly.

Welcome to my other publishing channels