Use orElseGet instead of orElse in Optional

Lejdi Prifti
2 min readSep 11, 2023

--

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.

  1. 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 optionalPlayeris null.

Thanks for reading!

--

--

Lejdi Prifti
Lejdi Prifti

Written by Lejdi Prifti

Senior Software Engineer @ Linfa | Building high-quality software solutions

No responses yet