Optional은 null-safe 한 코드를 작성할 때 주로 이용됩니다.
데이터를 받아왔을 때 null 일 경우 orElse(), orElseGet()을 사용해 처리를 하는데 둘에 작지만 큰 차이점이 있으니 꼭 알고 써야 합니다.
isPresent() - get() 형식도 있지만 가시성 좋고 간결한 코드를 사용합시다.
요약
1. orElse()는 Optional의 값과 상관없이 항상 메소드를 실행한다.
2. orElseGet() 은 Optional이 null 일 때 메소드가 실행된다.
orElse() vs orElseGet()
public T orElse(T other) {
return value != null ? value : other;
}
public T orElseGet(Supplier<? extends T> supplier) {
return value != null ? value : supplier.get();
}
orElse()와 orElseGet()의 코드인데 supplier 빼고 다를 게 없는데? 할 수 있지만 그 supplier 때문에 차이가 나게 됩니다.
orElse()
public T orElse(T other) {
return value != null ? value : other;
}
`
//orElse
User user = userService.findById(id)
.orElse(userService.save(new User()));
id로 User 데이터를 찾는데, 찾으려는 user 데이터가 없다면 orElse()로 새로운 유저를 저장하고 받는 코드를 작성하려 합니다.
orElse()의 코드를 보면 value의 null 체크를 한 후, value나 other를 리턴 하지만
value가 null이 아닐 때 value를 리턴해도 other는 이미 실행된 상태입니다.
그림에 대입해서 보면,
userServise.save(new User()) 실행됨 -> findById로 데이터를 찾아옴 -> orElse에서 null 체크를 하고 데이터를 리턴함.
Optional이 null이 아니라면 찾아온 user를 리턴 하지만 새로운 user는 저장되어 남아있게 됩니다.
여기서 orElseGet()을 살펴봅시다.
orElseGet()
orElseGet()을 살펴보기 전에 일단 Supplier에 대해 알아야 합니다
public interface Supplier<T> {
T get();
}
단순히 get()만 제공하는 코드인데 이 때문에 차이가 발생하게 됩니다.
메소드가 자체적으로 실행되는 게 아닌 get()을 이용해야만 실행할 수 있기 때문입니다.
orElseGet()을 보면.
public T orElseGet(Supplier<? extends T> supplier) {
return value != null ? value : supplier.get();
}
`
//orElseGet
User user = userService.findById(id)
.orElseGet(() -> userService.save(new User()));
위의 orElse()와 마찬가지의 코드입니다. 하지만 null 체크 후 리턴하는 데이터가 supplier.get()입니다.
orElseGet() 내부의 메소드는 supplier로 제공되고, get()으로 호출하기 전까지 실행되지 않습니다.
따라서 orElseGet()에서 value가 null 일 때 spplier에서 제공된 메소드를 get()으로 실행시킨 후 리턴하게 됩니다.
그림에 대입해서 보면,
userServise.save(new User()) 가 제공됨 -> findById로 데이터를 찾아옴 -> optional이 null 일 경우 get()으로 메소드를 실행시킨 후 리턴함.
결국 orElseGet()은 null 일 경우에만 내부 메소드를 get()으로 실행시킨다는 결론이 납니다.
마무리
제가 의도한 코드에서 orElse(), orElseGet() 모두 같은 결과를 도출하지만 orElse()의 경우 불필요한 코드가 실행되게 됩니다.
로그를 찍거나 하는 간단한 코드일 경우에는 미미하겠지만, 위의 코드처럼 save를 하는 경우에는 필요 없는 데이터가 DB에 계속 쌓이게 됩니다.
orElse()가 필요할 때도 있겠지만, 되도록이면 지양하고 orElseGet()을 사용하는 게 좋을 것 같습니다.
박준호 / 선임연구원
Junho Park / 서비스R&D팀
'Spring Boot' 카테고리의 다른 글
[Spring Security] Run-As로 임시 권한 부여하기 (0) | 2022.08.19 |
---|---|
hikariCP 커넥션 누수 탐지 및 QueryDsl의 transform 커넥션 누수 이슈 해결 (0) | 2022.08.12 |
[Spring Boot] WebSecurityConfigurerAdapter Deprecated 대처 (1) | 2022.08.10 |
[튜토리얼] IntelliJ로 CRUD 구현하기 (0) | 2022.08.08 |
[튜토리얼] IntelliJ로 Hello World 찍기 (0) | 2022.08.08 |