Short Answer:
- orElse() will always call the given function whether you want it or not, regardless of
Optional.isPresent()value - orElseGet() will only call the given function when the
Optional.isPresent() == false
In real code, you might want to consider the second approach when the required resource is expensive to get.
Copy// Always get heavy resource
getResource(resourceId).orElse(getHeavyResource());
// Get heavy resource when required.
getResource(resourceId).orElseGet(() -> getHeavyResource())
For more details, consider the following example with this function:
Copypublic Optional<String> findMyPhone(int phoneId)
The difference is as below:
Copy X : buyNewExpensivePhone() called
+ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ+ββββββββββββββ+
| Optional.isPresent() | true | false |
+ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ+ββββββββββββββ+
| findMyPhone(int phoneId).orElse(buyNewExpensivePhone()) | X | X |
+ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ+ββββββββββββββ+
| findMyPhone(int phoneId).orElseGet(() -> buyNewExpensivePhone()) | | X |
+ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ+ββββββββββββββ+
When optional.isPresent() == false, there is no difference between two ways. However, when optional.isPresent() == true, orElse() always calls the subsequent function whether you want it or not.
Finally, the test case used is as below:
Result:
Copy------------- Scenario 1 - orElse() --------------------
1.1. Optional.isPresent() == true (Redundant call)
Going to a very far store to buy a new expensive phone
Used phone: MyCheapPhone
1.2. Optional.isPresent() == false
Going to a very far store to buy a new expensive phone
Used phone: NewExpensivePhone
------------- Scenario 2 - orElseGet() --------------------
2.1. Optional.isPresent() == true
Used phone: MyCheapPhone
2.2. Optional.isPresent() == false
Going to a very far store to buy a new expensive phone
Used phone: NewExpensivePhone
Code:
Copypublic class TestOptional {
public Optional<String> findMyPhone(int phoneId) {
return phoneId == 10
? Optional.of("MyCheapPhone")
: Optional.empty();
}
public String buyNewExpensivePhone() {
System.out.println("\tGoing to a very far store to buy a new expensive phone");
return "NewExpensivePhone";
}
public static void main(String[] args) {
TestOptional test = new TestOptional();
String phone;
System.out.println("------------- Scenario 1 - orElse() --------------------");
System.out.println(" 1.1. Optional.isPresent() == true (Redundant call)");
phone = test.findMyPhone(10).orElse(test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
System.out.println(" 1.2. Optional.isPresent() == false");
phone = test.findMyPhone(-1).orElse(test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
System.out.println("------------- Scenario 2 - orElseGet() --------------------");
System.out.println(" 2.1. Optional.isPresent() == true");
// Can be written as test::buyNewExpensivePhone
phone = test.findMyPhone(10).orElseGet(() -> test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
System.out.println(" 2.2. Optional.isPresent() == false");
phone = test.findMyPhone(-1).orElseGet(() -> test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
}
}
Answer from Hoa Nguyen on Stack OverflowShort Answer:
- orElse() will always call the given function whether you want it or not, regardless of
Optional.isPresent()value - orElseGet() will only call the given function when the
Optional.isPresent() == false
In real code, you might want to consider the second approach when the required resource is expensive to get.
Copy// Always get heavy resource
getResource(resourceId).orElse(getHeavyResource());
// Get heavy resource when required.
getResource(resourceId).orElseGet(() -> getHeavyResource())
For more details, consider the following example with this function:
Copypublic Optional<String> findMyPhone(int phoneId)
The difference is as below:
Copy X : buyNewExpensivePhone() called
+ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ+ββββββββββββββ+
| Optional.isPresent() | true | false |
+ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ+ββββββββββββββ+
| findMyPhone(int phoneId).orElse(buyNewExpensivePhone()) | X | X |
+ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ+ββββββββββββββ+
| findMyPhone(int phoneId).orElseGet(() -> buyNewExpensivePhone()) | | X |
+ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ+ββββββββββββββ+
When optional.isPresent() == false, there is no difference between two ways. However, when optional.isPresent() == true, orElse() always calls the subsequent function whether you want it or not.
Finally, the test case used is as below:
Result:
Copy------------- Scenario 1 - orElse() --------------------
1.1. Optional.isPresent() == true (Redundant call)
Going to a very far store to buy a new expensive phone
Used phone: MyCheapPhone
1.2. Optional.isPresent() == false
Going to a very far store to buy a new expensive phone
Used phone: NewExpensivePhone
------------- Scenario 2 - orElseGet() --------------------
2.1. Optional.isPresent() == true
Used phone: MyCheapPhone
2.2. Optional.isPresent() == false
Going to a very far store to buy a new expensive phone
Used phone: NewExpensivePhone
Code:
Copypublic class TestOptional {
public Optional<String> findMyPhone(int phoneId) {
return phoneId == 10
? Optional.of("MyCheapPhone")
: Optional.empty();
}
public String buyNewExpensivePhone() {
System.out.println("\tGoing to a very far store to buy a new expensive phone");
return "NewExpensivePhone";
}
public static void main(String[] args) {
TestOptional test = new TestOptional();
String phone;
System.out.println("------------- Scenario 1 - orElse() --------------------");
System.out.println(" 1.1. Optional.isPresent() == true (Redundant call)");
phone = test.findMyPhone(10).orElse(test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
System.out.println(" 1.2. Optional.isPresent() == false");
phone = test.findMyPhone(-1).orElse(test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
System.out.println("------------- Scenario 2 - orElseGet() --------------------");
System.out.println(" 2.1. Optional.isPresent() == true");
// Can be written as test::buyNewExpensivePhone
phone = test.findMyPhone(10).orElseGet(() -> test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
System.out.println(" 2.2. Optional.isPresent() == false");
phone = test.findMyPhone(-1).orElseGet(() -> test.buyNewExpensivePhone());
System.out.println("\tUsed phone: " + phone + "\n");
}
}
Take these two scenarios:
CopyOptional<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.
Videos
This is part of JDK 9 in the form of method 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, this post I wrote, or ticket JDK-8080418 where this method was introduced.
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.