A fallback value may be cheap, such as a short string. It may also require reading configuration, performing a calculation, or calling another component. Java’s Optional API lets developers express these situations differently.
The distinction between orElse() and orElseGet() is especially important when producing the fallback involves work. Both can supply a result for an empty optional, but they do not evaluate a method-call expression in the same way.
A method argument is evaluated before the call
Consider:
String label = optionalLabel.orElse(loadDefaultLabel());
Java evaluates the argument expression before invoking orElse(). Consequently, loadDefaultLabel() runs even when the optional already contains a value.
This follows Java’s ordinary method-invocation rules, rather than a special behavior unique to Optional. The Java Language Specification describes argument expressions being evaluated to obtain the values passed to a method.
The returned label can therefore be correct while unnecessary work has still occurred.
That makes this issue easy to miss in tests that check only the final string.
Use a supplier when the work should be conditional
The alternative is:
String label = optionalLabel.orElseGet(() -> loadDefaultLabel());
Oracle documents that orElseGet() returns the contained value when one is present. Otherwise, it obtains the result from the supplied function.
Here, the lambda’s body expresses work to perform if the optional is empty.
For a simple constant, orElse(“Untitled”) remains clear and appropriate. There is no need to turn every default into a supplier merely to follow a blanket rule.
Choose based on whether you are passing an already available value or describing work that should happen only when necessary.
Inspect side effects as well as cost
Imagine a fallback method that increments a metric whenever it loads a default configuration. With eager evaluation, that metric may increase even when the application uses the value already present.
Another fallback might write a log entry, open a resource, or fail with an exception. Unnecessary evaluation then affects more than performance.
A practical review should inspect what the fallback actually does. A harmless-looking method name can hide a call to another service.
If the work is mandatory regardless of whether a value is present, express that requirement separately. Hiding required work inside a fallback expression makes the code’s purpose difficult to understand.
Test both paths explicitly
Use a populated optional and an empty optional in focused tests. Check the selected value and whether the fallback operation ran.
For the supplier-based version, the populated case should use the existing value without invoking the fallback body. The empty case should exercise the fallback and verify the intended result.
Keep failure behavior visible too. If loading the default can fail, decide how the surrounding workflow should respond.
Readable code separates the ordinary path from exceptional or expensive work. Optional can help express that distinction, but only when the fallback method matches the intended timing. The choice between orElse() and orElseGet() is therefore a small API decision with a concrete effect on what the application actually does.

