티스토리 뷰
Java 8 도입 이후에 Optional을 활용하면서 자주 사용하는 orElse(), orElseGet()의 차이점을 알아보겠습니다.
1. orElse(), orElseGet() 이란?
orElse(), orElseGet 구현 코드
실제로 orElse()와 orElseGet()의 코드를 살펴보자.
/**
* If a value is present, returns the value, otherwise returns
* {@code other}.
*
* @param other the value to be returned, if no value is present.
* May be {@code null}.
* @return the value, if present, otherwise {@code other}
*/
public T orElse(T other) {
return value != null ? value : other;
}
/**
* If a value is present, returns the value, otherwise returns the result
* produced by the supplying function.
*
* @param supplier the supplying function that produces a value to be returned
* @return the value, if present, otherwise the result produced by the
* supplying function
* @throws NullPointerException if no value is present and the supplying
* function is {@code null}
*/
public T orElseGet(Supplier<? extends T> supplier) {
return value != null ? value : supplier.get();
}
예제 코드를 확인해보면 value가 null이 아니면 value를 return해주고, null인 경우 인자로 들어온 값을 return 해주는 함수라는 것을 알 수 있다. 코드상의 차이점은 orElse()의 경우는 값을 파라미터로, orElseGet()의 경우 Supplier를 파라미터로 받고있다는 것이다.
orElse(), orElseGet() 예제코드
public void getNameTest() {
String name = "roopre";
String result1 = Optional.ofNullable(name).orElseGet(() -> defaultName());
String result2 = Optional.ofNullable(name).orElse(defaultName());
String nullName = null;
String resultWithNull1 = Optional.ofNullable(nullName).orElseGet(() -> defaultName());
String resultWithNull2 = Optional.ofNullable(nullName).orElse(defaultName());
}
private String defaultName() {
System.out.println("call");
return "default";
}
result1, result2는 모두 "roopre"로 같다. 하지만 resultWithNull1, resultWithNull2는 "default"로 같다.
이를 통해 orElse(), orElseGet()은 모두 name과 nullName이 null이 아닌 경우 그대로 반환해주고 null인 경우 뒤에 인자값을 반환해주는 것을 알 수 있다.
출력값을 살펴보면, orElse() 호출 시에는 value가 null인지 관계 없이 무조건 defaultName()이 호출되어 call이 출력된다는 사실을 알 수 있다. 반대로 orElseGet()은 null인 경우에만 defaultName()이 호출된다.
왜 orElse()는 항상 defaultName() 메서드를 호출하는지 살펴보자. 실제 구현부를 살펴보면 orElse()는 T other 즉 defaultName() 메서드의 return값을 인자로 받고있다. 따라서 메서드를 실행시켜 return 값을 T other에 바인딩 해야하기때문에 null 여부를 따지기 전에 항상 메서드를 실행시킨다.
public T orElse(T other) {
return value != null ? value : defaultName();
}
정리하면 다음과 같다.
- orElse() 메소드는 해당 값이 null이거나 null이 아니어도 실행된다.
- orElseGet() 메소드는 해당 값이 null인 경우에만 실행된다.
불필요하게 호출되는 경우 외에는 큰 차이가 없지만, 실제 프로젝트에서 심각한 이슈를 가져올 수 있다.
public void findUserByEmail(String email, String password) {
userRepository.findByEmail(email).orElse(createUser(email, password));
}
private User createUser(String email, password) {
return userRepository.save(User.createUser(email, password));
}
위 예제코드는 email을 통해 User를 조회하고 해당하는 User가 없으면 email과 password로 User 객체를 생성해 데이터베이스에 저장 후 반환하는 상황을 보여준다. 만약에, email이 Unique한 경우를 생각해보자. 여기서 해당 email을 가지는 user 존재 유무 상관없이 createUser() 메서드가 실행되고 해당 email, password를 가지는 User를 생성해 저장을 시도하게 된다. email이 이미 존재하는 경우에는 unique 제약으로 인해 exception이 발생하게된다.
이는 다시 orElseGet()을 활용해 아래와 같이 수정할 수 있다.
public void findUserByEmail(String email, String password) {
userRepository.findByEmail(email).orElseGet(() -> createUser(email, password));
}
private User createUser(String email, password) {
return userRepository.save(User.createUser(email, password));
}
'Java' 카테고리의 다른 글
[Java] JDBC 사용하기 (MySQL) (0) | 2023.01.26 |
---|---|
[Java] Socket 통신 개념과 활용 (0) | 2023.01.09 |