Optional orElse vs orElseGet
Optional의 orElse와 orElseGet의 차이를 알아봅니다.
Goal
- Optional의 orElse와 orElseGet의 차이를 알아봅니다.
- 특히 JPA를 사용하는 경우 주의할점을 알아봅니다.
null 일때의 동작이 다릅니다.
OrElse는 항상 동작합니다.orElseGet은 null인 경우에만 동작 합니다.

docs에도 써있는 내용이지만, 실제 메소드의 구현체를 한번 보겠습니다.
- 여기서 유심히 봐야하는것은, 인자와 반환값입니다.
orElse의 경우 반환해야할값을 인자로 그냥 받지만,orElseGet의 경우 Supplier로 한번더 wrapping 된것을 인자로 받습니다.orElse의 경우에는 반환값이 객체이므로, 들어온 메소드를 일단 실행 시켜버립니다.orElseGet의 경우에는 Supplier 형태이므로 인자로 들어온 객체가 null인 경우에만,get()을 호출해 생성된 값을 반환합니다.
1 | |
- 밑에서 설명할 예제를 미리 살짝 보겠습니다.
orElse,orElseGet둘다 넣어주는 것은 method 입니다.- 하지만
orElse의 경우는 반환해야하는 타입과, 인자 타입이 객체이므로 일단 메소드를 실행시켜 버리게 됩니다.
JPA를 사용할때 조심해야할점
find시 Optional 형태의 값을 반환받게 되므로 주의해야합니다.
1 | |
1 | |
getMember()에서는 인자로 들어온 이름을 가진 멤버가 있다면 바로 불러오고, 해당 이름을 가진 유저가 없는 경우 에 인자로 들어온 이름을 가진 유저를 생성해서 저장하는것을 의도했습니다.
- 실제로는 이미
setUp()에서 동일한 이름인 unluckyjung 이라는 유저가 있으니saveMember가()호출되지 않길 기대하겠죠. - 중복 저장이 되지 않고, 기존의 유저 한개만 계속 DB에 저장될테니
findAll()시 1개 의 유저정보만 불려오는것을 기대합니다.


-
하지만 테스트 코드를 돌려보면 1개가 아닌 2개의 Member가 저장되어있어 테스트에 실패하고, 로그를 통해
saveMember()메서드가 호출되는것도 알수 있습니다. -
의도했던것과 완전히 다르게 작동하는것이죠.
의도한대로 수정하는 방법은 아주 간단합니다.
1 | |
orElseGet()으로 바꿔주어 null인 경우에만 호출하도록 하면됩니다.- 이 예제를 통해서 알수 있는것은
orElse를 사용하는경우 비즈니스 로직에 버그를 유발할 가능성이 있고, 항상 메소드가 호출되니 성능적인 측면에서도 손해가 있을수 있다는것을 알 수 있습니다.
Conclusion
orElse는 Optional에 담겨있는값이 null이 아닌 경우에도 메소드를 호출합니다.orElse를 사용함으로 인해 일어날수 있는 버그나, 성능손해를 경계해야합니다. (특히 JPA 사용시)
Code
- 해당 코드들은 전부 github에서 보실 수 있습니다.
Reference
- https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#orElse-T-
- https://www.baeldung.com/java-optional-or-else-vs-or-else-get
- https://stackoverflow.com/questions/33170109/difference-between-optional-orelse-and-optional-orelseget