WeeklyStudy / modern-java-in-action

Modern Java in Action Study
0 stars 0 forks source link

Optional의 orElse() vs orElseGet() #26

Open ahah525 opened 1 year ago

ahah525 commented 1 year ago

문제

지금까지 Optional의 값을 꺼낼 때 안전하지 않은 get() 보다는 orElse() 주로 사용해왔다.

책에서 orElseGet(Supplier<? extends T> other)는 orElse 메서드에 대응하는 게으른 버전의 메서드다 라고 간단하게 설명하고 있는데, 한 번도 사용해본적이 없어서 추가적인 학습이 필요다고 느꼈다.

예제를 통해서 orElse와 orElseGet은 어떤 차이가 있는지 이해하고 어떠한 경우에 사용해야할 지 생각해보자.

관련 목차

참고자료

ahah525 commented 1 year ago

💡orElse()

값이 있으면 값을 반환하고, 없으면 기본값을 반환한다.

스크린샷 2023-08-15 오후 4 42 30

1. 값이 null이 아닌 경우

1.1. 예제 코드

@Test
@DisplayName("[orElse] null이 아닌 경우")
void t1() {
    String userEmail = "user1@naver.com";
    String result = Optional.ofNullable(userEmail)
            .orElse(getUserEmail());

    System.out.println(result);
}

1.2. 실행 흐름

  1. Optional.ofNullable() 이 호출되고 value가 "user1@naver.com"Optional 객체 생성
  2. getUserEmail() 이 호출되고 반환값을 orElse() 파라미터로 전달
  3. orElse() 가 호출되고 value가 null이 아니므로 "user1@naver.com" 를 반환

1.3. 출력 결과

getUserEmail() Called
user1@naver.com

2. 값이 null인 경우

2.1. 예제 코드

@Test
@DisplayName("[orElse] null인 경우")
void t2() {
    String userEmail = null;
    String result = Optional.ofNullable(userEmail)
            .orElse(getUserEmail());

    System.out.println(result);
}

2.2. 실행 흐름

1~2는 1.2 와 동일

  1. orElse() 가 호출되고 value가 null이므로 "user@naver.com" 를 반환

2.3. 출력 결과

getUserEmail() Called
user@naver.com

💡orElseGet()

값이 있으면 값을 반환하고, 없으면 supplier의 결과값을 반환한다.

스크린샷 2023-08-15 오후 4 42 56

1. 값이 null이 아닌 경우

1.1. 예제 코드

@Test
@DisplayName("[orElseGet] null이 아닌 경우")
void t3() {
    String userEmail = "user1@naver.com";
    String result = Optional.ofNullable(userEmail)
            .orElseGet(this::getUserEmail);

    System.out.println(result);
}

1.2. 실행 흐름

  1. Optional.ofNullable() 이 호출되고 value가 "user1@naver.com"Optional 객체 생성
  2. getUserEmail 함수 자체를 orElseGet() 파라미터로 전달
  3. orElse() 가 호출되고 value가 null이 아니므로 getUserEmail() 이 실행되지 않고 "user1@naver.com" 를 반환

1.3. 출력 결과

user1@naver.com

2. 값이 null인 경우

2.1. 예제 코드

@Test
@DisplayName("[orElseGet] null인 경우")
void t4() {
    String userEmail = null;
    String result = Optional.ofNullable(userEmail)
            .orElseGet(this::getUserEmail);

    System.out.println(result);
}

2.2. 실행 흐름

1~2는 1.2 동일

  1. orElse() 가 호출되고 value가 null이므로 getUserEmail() 가 실행되어 "user@naver.com" 를 반환

2.3. 출력결과

getUserEmail() Called
user@naver.com

💡orElse로 인한 문제를 orElseGet으로 해결하기

Username 이 unique 하다고 가정한다.

1. orElse로 인해 장애가 발생할 수 있는 예제

DB에 해당 name을 가진 User가 있든 없든 createUserWithName() 이 무조건 호출되기 때문에 중복된 name 인 경우 DB에 save 할 때 오류가 발생한다.

public User findByName(String name) {
        return userRepository.findByName(name)
                            .orElse(createUserWithName(name));
}

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

2. orElseGet으로 해결

DB에 해당 name을 가진 User가 있는 경우에는 조회된 User 객체를 반환하고 없는 경우에는 createUserWithName() 가 호출되어 새로 생성된 User 객체를 반환한다.

public User findByName(String name) {
        return userRepository.findByName(name)
                            .orElseGet(() -> createUserWithName(name));
}

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

💡결론

Reference