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.
The orElse() method of java. util. Optional class in Java is used to get the value of this Optional instance, if present. If there is no value present in this Optional instance, then this method returns the specified value.
Solution: Using Optional Class Optional. ofNullable() method of the Optional class, returns a Non-empty Optional if the given object has a value, otherwise it returns an empty Optional. We can check whether the returned Optional value is empty or non-empty using the isPresent() method.
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.
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.
Short Answer:
Optional.isPresent()
valueOptional.isPresent() == false
In real code, you might want to consider the second approach when the required resource is expensive to get.
// 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:
public Optional<String> findMyPhone(int phoneId)
The difference is as below:
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:
------------- 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:
public 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");
}
}
I reached here for the problem Kudo mentioned.
I'm sharing my experience for others.
orElse
, or orElseGet
, that is the question:static String B() {
System.out.println("B()...");
return "B";
}
public static void main(final String... args) {
System.out.println(Optional.of("A").orElse(B()));
System.out.println(Optional.of("A").orElseGet(() -> B()));
}
prints
B()...
A
A
orElse
evaluates the value of B() interdependently of the value of the optional. Thus, orElseGet
is lazy.
I would say the biggest difference between orElse
and orElseGet
comes when we want to evaluate something to get the new value in the else
condition.
Consider this simple example -
// oldValue is String type field that can be NULL
String value;
if (oldValue != null) {
value = oldValue;
} else {
value = apicall().value;
}
Now let's transform the above example to using Optional
along with orElse
,
// oldValue is Optional type field
String value = oldValue.orElse(apicall().value);
Now let's transform the above example to using Optional
along with orElseGet
,
// oldValue is Optional type field
String value = oldValue.orElseGet(() -> apicall().value);
When orElse
is invoked, the apicall().value
is evaluated and passed to the method. Whereas, in the case of orElseGet
the evaluation only happens if the oldValue
is empty. orElseGet
allows lazy evaluation.
First of all check the declaration of both the methods.
1) OrElse: Execute logic and pass result as argument.
public T orElse(T other) {
return value != null ? value : other;
}
2) OrElseGet: Execute logic if value inside the optional is null
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
Some explanation on above declaration: The argument of “Optional.orElse” always gets executed irrespective of the value of the object in optional (null, empty or with value). Always consider the above-mentioned point in mind while using “Optional.orElse”, otherwise use of “Optional.orElse” can be very risky in the following situation.
Risk-1) Logging Issue: If content inside orElse contains any log statement: In this case, you will end up logging it every time.
Optional.of(getModel())
.map(x -> {
//some logic
})
.orElse(getDefaultAndLogError());
getDefaultAndLogError() {
log.error("No Data found, Returning default");
return defaultValue;
}
Risk-2) Performance Issue: If content inside orElse is time-intensive: Time intensive content can be any i/o operations DB call, API call, file reading. If we put such content in orElse(), the system will end up executing a code of no use.
Optional.of(getModel())
.map(x -> //some logic)
.orElse(getDefaultFromDb());
getDefaultFromDb() {
return dataBaseServe.getDefaultValue(); //api call, db call.
}
Risk-3) Illegal State or Bug Issue: If content inside orElse is mutating some object state: We might be using the same object at another place let say inside Optional.map function and it can put us in a critical bug.
List<Model> list = new ArrayList<>();
Optional.of(getModel())
.map(x -> {
})
.orElse(get(list));
get(List < String > list) {
log.error("No Data found, Returning default");
list.add(defaultValue);
return defaultValue;
}
Then, When can we go with orElse()? Prefer using orElse when the default value is some constant object, enum. In all above cases we can go with Optional.orElseGet() (which only executes when Optional contains empty value)instead of Optional.orElse(). Why?? In orElse, we pass default result value, but in orElseGet we pass Supplier and method of Supplier only executes if the value in Optional is null.
Key takeaways from this:
I have explained this in point-2 (“Optional.map/Optional.orElse” != “if/else”) my medium blog. Use Java8 as a programmer not as a coder
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With