Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

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 these two and explore when to use each one.

2. Signatures

First, let’s start with the basics by looking at their signatures:

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.

Based on their Javadocs:

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

3. Differences

It’s easy to be a bit confused by these 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:

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

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

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 the below messages printed in the console:

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():

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

The above code won’t invoke the getRandomName() method.

Remember (from the Javadoc) that the Supplier method passed as an argument is only executed when an Optional value isn’t present.

Therefore, using orElseGet() for our case will save us the 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:

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

And orElseGet():

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

While executing our benchmark methods, we get:

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.

After all, orElse() involves the computation of the getRandomName() method for each run.

5. What’s Important?

Apart from the performance aspects, other factors worth considering include:

  • What if the method would execute some additional logic? E.g. making some DB inserts or updates
  • Even when we assign an object to the orElse() parameter, we’re still creating “Other” object for no reason:
    String name = Optional.of("baeldung").orElse("Other")

That’s why it’s important for us to make a careful decision between 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 directly accessible.

6. Conclusion

In this article, we learned the nuances between the Optional orElse() and OrElseGet() methods. We also discussed how such simple concepts can sometimes have a deeper meaning.

As always, the complete source code can be found over on Github.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.