목차
- 예시
- 큰 일 날 뻔한 사례
- 마치며
java8의 optional api 많이들 사용하실텐데요.
어찌보면 당연하지만 햇갈리는 내용에 대해 다뤄보겠습니다.
orElse와 orElseGet의 차이입니다.
귀찮으신분들을 위해 요약을 먼저 하자면
orElse는 null이던말던 항상 불립니다.
orElseGet은 null일 때만 불립니다.
예시
1 2 3 4 5 6
| String username = "이름"; String result1 = Optional.ofNullable(username).orElse("no name"); System.out.println(result1);
String result2 = Optional.ofNullable(username).orElseGet(() -> "no name"); System.out.println(result2);
|
위 두 println의 결과는 무엇일까요?
네 당연하게도 “이름” 입니다.
왜냐면 username != null 이기 때문이죠.
1 2
| String username = null;
|
그럼 위처럼 username == null 이면?
네. 당연하게도 둘다 “no name” 입니다.
그럼 같은거 아냐?
아닙니다. 아래의 경우를 생각해봅시다.
1 2 3 4 5 6 7 8 9 10 11 12
| public void ohMyGod() { String username = null; String result1 = Optional.ofNullable(username).orElse(getDefaultName()); System.out.println(result1);
String result2 = Optional.ofNullable(username).orElseGet(() -> getDefaultName()); System.out.println(result2); }
private String getDefaultName() { return "no name"; }
|
이 경우에 결과는 어떻게 될까요?
네. 둘다 “no name” 입니다. 결과는 같지만 여긴 굉장한 차이가 있습니다.
orElse의 경우는 “값”을 취합니다.
orElseGet은 “Supplier”를 취하죠.
위의 예시는 아래 코드로 다시 쓰여질 수 있습니다.
1 2 3 4 5 6 7 8
| String username = null; String defaultName = getDefaultName(); String result1 = Optional.ofNullable(username).orElse(defaultName); System.out.println(result1);
Supplier<String> supplier = () -> getDefaultName(); String result2 = Optional.ofNullable(username).orElseGet(supplier); System.out.println(result2);
|
아시겠나요?
orElse는 null이던말던 항상 불립니다.
orElseGet은 null일 때만 불립니다.
위의 예시에서는 ‘그래서 뭐?’ 라고 생각하시겠지만 아래의 경우를 한 번 봅시다.
실제 이것 때문에 장애를 낼 뻔한 적이 있습니다.
큰 일 날 뻔한 사례
1 2 3 4 5 6 7 8 9
| public User findByUsername(String name) { return userRepository.findByName(name).orElse(createUserWithName(name)); }
private User createUserWithName(String name) { User newUser = new User(); newUser.setName(name) return userRepository.save(user); }
|
(대충 이런 상황이었습니다.)
만약 user 테이블의 name이 unique였다면?
네. 맞습니다. 장애입니다. 왜냐면 아래랑 같기 때문이죠.
1 2 3 4 5 6 7 8 9 10
| public User findByUsername(String name) { User newUser = createUserWithName(name); return userRepository.findByName(name).orElse(newUser); }
private User createUserWithName(String name) { User newUser = new User(); newUser.setName(name) return userRepository.save(user); }
|
이해가 되시나요?
마치며
참 당연한건데 햇갈리는 경우가 있습니다.
버그는 정말 사소한것에서 부터 옵니다. 조심합시다.