Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optional orElse Optional in Java

People also ask

How does orElse work with Optional?

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.

What is the difference between orElse and orElseGet?

orElse method will be executed no matter Optional is null or not, however, orElseGet method will be only executed when Optional is null.

What is Optional of Java?

In Java, an Optional object is a container object which may or may not contain a value. The Optional class is present in the java. util package.

What is Java Optional ofNullable?

What is the ofNullable() method of the Optional class? The ofNullable() method is used to get an instance of the Optional class with a specified value. If the value is null , then an empty Optional object is returned.


This is part of JDK 9 in the form of or, which takes a Supplier<Optional<T>>. Your example would then be:

return serviceA(args)
    .or(() -> serviceB(args))
    .or(() -> serviceC(args));

For details see the Javadoc or this post I wrote.


The cleanest “try services” approach given the current API would be:

Optional<Result> o = Stream.<Supplier<Optional<Result>>>of(
    ()->serviceA(args), 
    ()->serviceB(args), 
    ()->serviceC(args), 
    ()->serviceD(args))
.map(Supplier::get)
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst();

The important aspect is not the (constant) chain of operations you have to write once but how easy it is to add another service (or modify the list of services in general). Here, adding or removing a single ()->serviceX(args) is enough.

Due to the lazy evaluation of streams, no service will be invoked if a preceding service returned a non-empty Optional.


Starting with Java 9, you can simplify the code to

Optional<Result> o = Stream.<Supplier<Optional<Result>>>of(
    ()->serviceA(args), 
    ()->serviceB(args), 
    ()->serviceC(args), 
    ()->serviceD(args))
.flatMap(s -> s.get().stream())
.findFirst();

though this answer already contains an even simpler approach for JDK 9.

JDK 16 offers the alternative

Optional<Result> o = Stream.<Supplier<Optional<Result>>>of(
    ()->serviceA(args), 
    ()->serviceB(args), 
    ()->serviceC(args), 
    ()->serviceD(args))
.<Result>mapMulti((s,c) -> s.get().ifPresent(c))
.findFirst();

though this approach might be more convenient with service methods accepting a Consumer rather than returning a Supplier.


It's not pretty, but this will work:

return serviceA(args)
  .map(Optional::of).orElseGet(() -> serviceB(args))
  .map(Optional::of).orElseGet(() -> serviceC(args))
  .map(Optional::of).orElseGet(() -> serviceD(args));

.map(func).orElseGet(sup) is a fairly handy pattern for use with Optional. It means "If this Optional contains value v, give me func(v), otherwise give me sup.get()".

In this case, we call serviceA(args) and get an Optional<Result>. If that Optional contains value v, we want to get Optional.of(v), but if it is empty, we want to get serviceB(args). Rinse-repeat with more alternatives.

Other uses of this pattern are

  • .map(Stream::of).orElseGet(Stream::empty)
  • .map(Collections::singleton).orElseGet(Collections::emptySet)

Perhaps this is what you're after: Get value from one Optional or another

Otherwise, you may want to have a look at Optional.orElseGet. Here's an example of what I think that you're after:

result = Optional.ofNullable(serviceA().orElseGet(
                                 () -> serviceB().orElseGet(
                                     () -> serviceC().orElse(null))));