[Java] Optional의 orElse()와 orElseGet()

Supplier

Supplier 함수적 인터페이스는 매개값은 없고 리턴값이 있는 getXXX() 메소드를 가지고 있습니다. 이 메소드들은 호출한 곳으로 데이터를 리턴(공급)하는 역할을 수행합니다.

1
2
3
4
5
6
7
IntSupplier intSupplier = () ->{
    int num = (int) (Math.random() * 6) + 1; // 주사위 눈금
    return num;
};

int num = intSupplier.getAsInt();
System.out.println(num);

Optional

1
2
3
4
5
6
String test = "test";
Optional<String> optNotNull = Optional.of(test);  // 인자로 null 값을 받지 않음
test = null;
Optional<String> optCanBeNull = Optional.ofNullable(test); // 인자로 null 값을 받을 수 있음
optNotNull.isPresent(); // null인지 체크
optCanBeNull.isPresent(); // null인지 체크
  • #of() : 인자로 null 값을 받을 수 없음
  • #ofNullable() : 인자로 null 값을 받을 수 있음
  • #isPresent() : null인지 체크
  • #orElse() : null 여부와 상관없이 항상 불린다.
  • #orElseGet() : null일 때만 불린다.

개발 의도

null을 반환하면 에러를 유발할 가능성이 높은 상황에서 메서드의 반환 타입으로 Optional을 사용하자는 것이 Optional을 만든 주된 목적입니다.

orElse()와 orElseGet()의 차이

  • #orElse() : null 여부와 상관없이 항상 불린다.
  • #orElseGet() : null일 때만 불린다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public User findByUsername(String name) {
  // user 정보가 존재해도 같은 이름의 유저를 생성
  // User.name column이 unique 조건이었다면 장애의 원인

  // 동일한 이름을 가진 여러 개의 유저 정보에 흩어져 저장된 데이터들을
  // 어떤 기준으로 정보를 통합해야는지 고민해야하는
  // 어려운 상황이 발생할 수 있음!
  // return userRepository.findByName(name).orElse(createUserWithName(name));
  Supplier<User> userSupplier = () -> createUserWithName(name);
  return userRepository.findByName(name).orElseGet(userSupplier);
  // return userRepository.findByName(name).orElseGet(() -> createUserWithName(name));
  
}

private User createUserWithName(String name) {
	User newUser = new User();
	newUser.setName(name)
	return userRepository.save(user);
}

orElse()는 무조건 실행되고, orElseGet()은 null일 때만 호출됩니다. 그리고 orElseGet()은 인자로 Supplier를 받습니다.

새로운 객체를 생성하거나 새로운 연산을 수행하는 경우 orElse() 대신 orElseGet()을 사용해야합니다. Optional에 값이 존재할 때 orElse()에서 새로운 객체를 생성하면 orElse()에서 생성된 객체는 버려지고, Optional의 값이 반환됩니다. Optional의 값이 null일 때만 동작하는 코드가 되기 때문에 피해야 합니다.

Reference

Leave a comment