Being lazy in Java with orElseGet
Optionals
are really cool Java 8 feature. But it works differently than I thought.
So I’ll show how I have shot my own leg when working with orElse
.
public static void main(String[] args) {
Client client = findClientInDatabase()
.orElse(createAndSaveNewClient());
}
private static Optional<Client> findClientInDatabase() {
System.out.println("Searching for client in database");
return Optional.of(new Client());
}
private static Client createAndSaveNewClient() {
System.out.println("Creating new client");
return new Client();
}
This code should find the client or it should create new client only if a client does not exist.
Output:
Searching for client in database
Creating new client
As you can see it works differently, then I have expected.
orElse
clause is always evaluated and the result is calculated.
orElseGet to the rescue
orElseGet
takes supplier function instead of value. And this supplier function
is executed lazily only when Optional value is empty
.
public static void main(String[] args) {
Client client = findClientInDatabase()
.orElseGet(() -> createAndSaveNewClient());
}
private static Optional<Client> findClientInDatabase() {
System.out.println("Searching for client in database");
return Optional.of(new Client());
}
private static Client createAndSaveNewClient() {
System.out.println("Creating new client");
return new Client();
}
Searching for client in database
Conclusion
It is really easy to introduce bug because of orElse
value is always calculated.
This example was taken from a real-world situation. I have almost merged code which
persisted a new entity to the database, even when an entry with the same name has already existed.
Thankfully integration tests have caught it.
Use orElse
mindfully, I would recommend using orElse
only when value is
constant or when orElse
clause won’t have side effects. orElseGet
solves
this issue by loading values lazily.