Difference Between 'Optional.Orelse()' and 'Optional.Orelseget()'

Difference between `Optional.orElse()` and `Optional.orElseGet()`

Take these two scenarios:

Optional<Foo> opt = ...
Foo x = opt.orElse( new Foo() );
Foo y = opt.orElseGet( Foo::new );

If opt doesn't contain a value, the two are indeed equivalent. But if opt does contain a value, how many Foo objects will be created?

P.s.: of course in this example the difference probably wouldn't be measurable, but if you have to obtain your default value from a remote web service for example, or from a database, it suddenly becomes very important.

When to use Optional.orElse() rather than Optional.orElseGet()

  1. In most cases, you type less when using orElse, since it is shorter than orElseGet and, compare the signatures of them:

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

a Supplier<? extends T> other is most likely longer than T other. If the performance is not so critical you may choose to type less. Programmer's effort also counts :-) For example, compare:

orElseGet(() -> 1)
orElse(1)

  1. As your link has mentioned:

by default, it makes more sense to use orElseGet() every time unless
the default object is already constructed and accessible directly.

When I need to use Optional.orElseGet() over Optional.orElse()

I think I am starting to understand your question. Execution order with Optional can be different from what we are used to in procedural programming (the same is true for Java streams and other code using lambdas).

I will use the two examples from Eugene’s answer:

    o1.orElse(new MyObject()); // 1055e4af 

This is plain old Java: it’s a call to orElse() taking new MyObject() as argument. So the argument is evaluated first and a new MyObject created. This is then passed to orElse(). orElse() looks to see whether a value is present in the Optional; if so it returns that value (discarding the newly created object); if not, it returns the object given to it in the argument. This was the simpler example.

    o1.orElseGet(() -> {
System.out.println("Should I see this");
return new MyObject();
});

Again we have a method call with one argument, and again the argument is evaluated first. The lambda is only created and passed as a supplier. The code inside { } is not executed yet (you also see no Should I see this in Eugene’s output). Again orElseGet looks to see if there is a value present in the Optional. If there is, the value is returned and the supplier we passed is ignored. If there isn’t, the supplier is invoked, the code inside { } is executed to get the value to be returned from orElseGet().

In the first case, one may say that a MyObject is created and wasted. In the second a Supplier is created and wasted. What you get in return is terse and null-pointer safe code in both cases. So very often it’s not important which one you pick. If creating the MyObject is costly or has unwanted side effects, you will of course want the second version where the object is only created when it is asked for, and is never wasted. Eugene in a comment mentions the case where the returned object comes from a database call. Database calls are usually time-consuming enough that you don’t want to make one for no purpose.

Parameter of Optional.orElse gets called even when Optional contains value

The orElse method looks like this:

public T orElse(T other) {
return value != null ? value : other;
}

There isn't any complex logic here.

As with any method, it will do the following:

  • Get the actual values of all parameters passed to the method (which includes calling any methods in those parameters).
  • Pass those parameters to the method.
  • Execute the method.

The fact that we don't actually care about the value of the parameter doesn't change this process (this is just the way the language has been designed, for better or worse).


If you're looking to not call the method in the parameter, you're probably looking for Optional.orElseGet.

This:

public static void main(String[] args){
String o = Optional.ofNullable("world").map(str -> "hello" + str)
.orElseGet(() -> dontCallMe());
System.out.println(o);
}

private static String dontCallMe() {
System.out.println("should not have called");
return "why oh why";
}

Outputs only:

helloworld

The difference here is that the thing (Supplier) we're passing to the method will stay () -> dontCallMe(), it does not become () -> "why oh why" - only when you call get does it actually evaluate what's going on there and does dontCallMe actually get called.

using orElseGet vs orElse in Java8

Of course orElseGet() is preferable. orElse() would execute your service even when the OptionalDouble is not empty, which is wasteful (since menuService.findBySymbol(addWalletAmount.getMenuSymbol()).getPrice().doubleValue() is the argument passed to the orElse() method, and it must be evaluated before orElse() is executed).

orElseGet() would only execute your service if the OptionalDouble is empty.

Optional orElse Optional in Java

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.

Optional isPresent vs orElse(null)

You can also do:

expectedPackageRepository.findById(1).ifPresent(
ep -> {
ep.setDateModified(new Date());
expectedPackageRepository.saveAndFlush(ep);
}
);

Ideally, you would also extract the part between brackets ({}) to a separate method. Then, you could write like this:

    expectedPackageRepository.findById(1).ifPresent(this::doSomethingWithEp);

Where:

void doSomethingWithEp(ExpectedPackage ep) {
ep.setDateModified(new Date());
expectedPackageRepository.saveAndFlush(ep);
}

You can read the documentation of ifPresent here: https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#ifPresent-java.util.function.Consumer-

As it states, it will perform the specified action if the value is present and do nothing otherwise.

Defaulting Optional orElse with Optional.empty in Java 8

Combine both the list using Stream.of and check for element or return Optional.empty()

Stream.of(lunches, dinners)
.flatMap(List::stream)
.filter(s -> s.getName()
.equalsIgnoreCase(name))
.findFirst();

As per the suggestion from @Holger you can also use Stream.concat to concat two streams and then check for element

Stream.concat(lunches.stream(), dinners.stream())
.filter(s -> s.getName()
.equalsIgnoreCase(name))
.findFirst();

Java Optional evaluation side Effects

Why is the second option evaluated?

Because you're calling the second() method, in order to provide the value as an argument to orElse(). The value of the argument will be ignored (because you already have a value) but that doesn't mean it doesn't have to be provided.

Basically, this code:

first().orElse(second())

is equivalent to:

Optional<String> tmp1 = first();
Optional<String> tmp2 = second();
Optional<String> result = tmp1.orElse(tmp2);

There's nothing optional-specific here - that's how argument evaluation always works in Java.

Note that this is a big difference between a library construct (orElse) and the condition operator language construct (?:) which will only evaluate either the second or third operand, but never both.

As Artur mentioned, if you want to defer the call to second(), you need to use orElseGet, where the argument you pass isn't the value to use if first doesn't have one, but the call to make in order to get the value.



Related Topics



Leave a reply



Submit