Use orElseGet instead of orElse in Optional
In this short article, the main point I want to describe is to stop using orElse
and favor more orElseGet
when using Optional in Java.
Optional is a container that can hold either a non-null value or represent the absence of a value.
public class FootballPlayerService {
private List<FootballPlayer> players;
public FootballPlayerService() {
players = new ArrayList<>();
players.add(new FootballPlayer("Lionel Messi", 34));
players.add(new FootballPlayer("Cristiano Ronaldo", 36));
players.add(new FootballPlayer("Neymar Jr.", 29));
}
public Optional<FootballPlayer> findPlayerByName(String name) {
for (FootballPlayer player : players) {
if (player.getName().equalsIgnoreCase(name)) {
return Optional.of(player);
}
}
return Optional.empty();
}
}
In the example, above we return the player if it is found as an Optional
, otherwise we return an empty Optional
.
public class FootballPlayerService {
private List<FootballPlayer> players;
public FootballPlayerService() {
players = new ArrayList<>();
players.add(new FootballPlayer("Lionel Messi", 34));
players.add(new FootballPlayer("Cristiano Ronaldo", 36));
players.add(new FootballPlayer("Neymar Jr.", 29));
}
public FootballPlayer findPlayerByName(String name) {
Optional<FootballPlayer> optionalPlayer = players.stream()
.filter(player -> player.getName().equalsIgnoreCase(name))
.findFirst();
return optionalPlayer.orElseThrow(() -> new PlayerNotFoundException(name));
}
}
We could write the same function, but this time we return the FootballPlayer
object if it is found, and if not, we throw an exception. This really improves the code and makes it more readable, as we leverage also the benefits of the Stream
class.
However, sometimes you want to return a default object if the one that you are looking for cannot be found. There are two ways you can do it.
- orElse
public class FootballPlayerService {
private List<FootballPlayer> players;
public FootballPlayerService() {
players = new ArrayList<>();
players.add(new FootballPlayer("Lionel Messi", 34));
players.add(new FootballPlayer("Cristiano Ronaldo", 36));
players.add(new FootballPlayer("Neymar Jr.", 29));
}
public FootballPlayer findPlayerByName(String name) {
Optional<FootballPlayer> optionalPlayer = players.stream()
.filter(player -> player.getName().equalsIgnoreCase(name))
.findFirst();
return optionalPlayer.orElse(new FootballPlayer("Neymar Jr.", 29));
}
}
2. orElseGet
public class FootballPlayerService {
private List<FootballPlayer> players;
public FootballPlayerService() {
players = new ArrayList<>();
players.add(new FootballPlayer("Lionel Messi", 34));
players.add(new FootballPlayer("Cristiano Ronaldo", 36));
players.add(new FootballPlayer("Neymar Jr.", 29));
}
public FootballPlayer findPlayerByName(String name) {
Optional<FootballPlayer> optionalPlayer = players.stream()
.filter(player -> player.getName().equalsIgnoreCase(name))
.findFirst();
return optionalPlayer.orElseGet(() ->
new FootballPlayer("Neymar Jr.", 29));
}
}
Difference
The difference between the two is that despite of the condition that optionalPlayer
is null or not, the object inside orElse
will always be created. In fact, it is created before the conditon is evaluated. However, this is not the case for orElseGet
. The object is created only if the optionalPlayer
is null.
Thanks for reading!