Optional orElse() VS. orElseGet()

알파로그·2024년 1월 29일
0

JAVA 문법과 지식

목록 보기
9/9
post-custom-banner

✏️ 발단

JWT 를 사용한 회원가입, 로그인 비즈니스 로직을 만들어 PR 했는데 Optional 을 사용한 부분에서 orElse 를 사용한 의도에 대해서 피드백을 받았다.

지금까지 Optional 을 사용할 때 orElse 를 단순히 if 문의 else 처럼 사용하고 있었는데,
이번 기회에 더 디테일하게 알아보려고 정리하게 되었다.

// username 으로 Member 를 찾을 경우 반환
// 찾지 못하면 새로운 Member 를 저장 후 반환
public Member whenKakaoLogin(UserResponse response) {
    return this.findByUsername(response.getUsername())
            .orElse(this.createMember(response));
}

✏️ orElse() 와 orElseGet()

  • orElse 에 대해 알아보니 orElseGet 이라는 키워드를 발견했다.
    • Optional 객체에 작성된 주석을 살펴보니 대략 아래와 같았다.
      • orElse : null 일경우 파라미터값 (other) 이 반환됨
      • orElseGet : null 일경우 파라미터의 함수에서 생성된 결과를 반환함

📍 orElse 의 파라미터에 method 를 입력 할 경우

  • 가이드에 나온데로 orElse() 는 method 가아닌 값을 파라미터로 입력해야 한다.
    • 하지만 값이아닌 method 로 파라미터를 입력하면 어떻게 될까?
public Member whenKakaoLogin(UserResponse response) {
    return this.findByUsername(response.getUsername())
            .orElse(this.createMember(response));
}
  • 위 로직을 검증하기 위해 단위테스트 객체를 생성했다.
    • username 으로 조회할 경우 “user1” 이면 member 객체를, 아니면 null 을 반환하도록 만들었다.
@ExtendWith(MockitoExtension.class)
class MemberServiceTest {

    @InjectMocks
    MemberService memberService;

    @Mock
    MemberJpaRepository memberRepository;

    @BeforeEach
    void setup() {
        when(memberRepository.findByUsername(anyString()))
                .thenAnswer(invocation -> {
                    String username = (String) invocation.getArgument(0);

                    return username.equals("user1") ? Optional.of(createMember()) : Optional.empty();
                });

        when(memberRepository.save(any()))
                .thenReturn(createMember());
    }

📍 orElseGet 을 사용할 경우

  • username 으로 성공하는 Test 를 실행하니 예상과 다르게 Member 를 생성하는 로직까지 실행되버렸다.
    • 그 이유는 orElse 는 값을 파라미터로 요구하기 때문에 인자에 method 가 있다면 그 method 의 결과 값을 먼저 구해야하기 때문이다.
@Test
void no1() {
    String username = "user1";
    memberService.whenKakaoLogin(getUserResponse(username));
}

// 결과
MemberService -- Username 으로 조회 메서드 실행
MemberService -- Member 생성 메서드 실행
  • 로직을 orElseGet() 으로 수정하니 test 가 의도대로 조회 메서드만 실행된다.
    • orElseGet(Supplier) 에서 Supplier 는 Optional 에 값이 없을 때만 실행되기 때문에 의도대로 작동하게 된다.
public Member whenKakaoLogin(UserResponse response) {
    return this.findByUsername(response.getUsername())
            .orElseGet(() -> this.createMember(response));
}

// 결과
MemberService -- Username 으로 조회 메서드 실행
  • 물론 username 으로 조회를 할 수 없을 때도 의도대로 작동된다.
@Test
void no2() {
    String username = "user2";
    memberService.whenKakaoLogin(getUserResponse(username));
}

// 결과
MemberService -- Username 으로 조회 메서드 실행
MemberService -- Member 생성 메서드 실행

✏️ 결론

  • Optional 을 반환할 때 if 문을 사용하지 말자
  • Optional 이 null 일 때 → 값이라면 orElse() → 메서드라면 orElseGet()
profile
잘못된 내용 PR 환영
post-custom-banner

0개의 댓글