-
Optional, 그렇게 쓸꺼야🤔?스터디 노트 2023. 12. 5. 15:15
질의를 받았습니다. 여기에 왜 Optional을 쓰셨어요?
음? null을 방지하기 위해서...?
답변하기가 애매했습니다.
Optional은 왜 써야 할까요? 삼항연산자로 가볍게 처리하면 되는데 굳이 Optional을 써야만 하는걸까요?
📌 Optional이 뭡니까?
Java의 Optional은 null 값을 감싸서(Wrapping) 보다 안전하게 다루기 위한 목적으로 도입된 클래스입니다.
Optional의 기본 개념은 다음과 같습니다.
Optional은 null 값을 감싸는 객체입니다.
Optional은 값이 있는지 여부를 확인할 수 있습니다.
Optional에 값이 있는 경우, 값을 가져올 수 있습니다.
Optional에 값이 없는 경우, 지정된 값을 반환하거나, 지정된 함수를 호출하여 반환된 값을 반환할 수 있습니다.또한, Optional은 null 값을 처리하기 위한 다양한 메서드를 제공합니다. 다음은 메서드들을 간단하게 정리한 내용들입니다.
- of() : 값이 null이 아닌 경우에 사용합니다.
- ofNullable() : 값이 null일 수도 있는 경우에 사용합니다.
- isPresent() : Optional에 값이 있는지 여부를 확인합니다.
- get() : Optional에 있는 값을 가져옵니다.
- orElse() : Optional에 값이 없을 경우, 지정된 값을 반환합니다.
- orElseGet() : Optional에 값이 없을 경우, 지정된 함수를 호출하여 반환된 값을 반환합니다.📌 먼저 쓰면 좋은 점
먼저 Optional을 쓰면 좋은 점에 대해 생각해보겠습니다. Optional은 본디 위험한 value인 null을 안전하게 다루기 위해 도입된 클래스입니다.
null을 warpping하여 안전하게 Exception을 발생시키지 않는 형태로 비즈니스를 진행하는 것이죠.
박스포장 정도로 생각하시면 될 것 같습니다.
하지만 그 안에 value가 있는지 비어있는지는 모르는 상황이 되어버리는 것이죠.
그럼 Optional을 쓰면 뭐가 좋을까요?
✅ NullPointerException을 방지합니다.
Java에서 nulll이란 것은 친숙하면서도 치명적인 값입니다. 예외를 발생시킬 수 있기 때문이죠. RuntimeException을 상속받고 있기에 언체크드 익셉션으로 컴파일 시 오류를 잡을 수 없습니다.
즉, 애플리케이션이 실행되는 중 발생할 수 있는 Exception의 한 종류라는 것이죠..😖(섬뜩)
✅ 가독성을 향상시킵니다.
이 부분은 사용하는 사람에 따라 다르긴 하겠지만, 코드를 조금 더 깔끔하게 구성할 수 있습니다.
하지만 이것의 정반대의 사유로 Optional이 안티패턴의 사유가 되기도 합니다.
결국 Optional을 쓰는 가장 큰 이유는 null을 반환할 가능성이 높은 메소드에서 'null Value를 안전하게 다루기 위함'이라고 할 수 있습니다.
대표적으로는 DB에서 값을 조회할 경우나 비즈니스 로직 중에 발생하는 Aggregation Data의 Value가 null로 의심될 때 사용하면 안전하고 단단하게 애플리케이션을 구성할 수 있겠지요.
📌 그럼 왜 쓰면 안되는가?
그럼 왜 Optional은 쓰면 안될까요?
일단 Optional은 위에서 말씀드렸던 것 처럼 null을 wrapping하여 사용합니다. 즉, 추가적인 메모리의 사용과 더불어 지불되는 가격이 더 높다는 단점이 있습니다.
또한 Optional 내부에 정상적인 Value가 들어있는지 Null이 들어있는지 모호해집니다.
그렇기 때문에 곧장 .get()으로 접근을 하게 되면 기껏 NullPointerException을 대비하기 위해 구현했던 Optional을 순식간에 꿔다 놓은 보릿자루 처럼 만들어버리는 것이죠.
만약 우리가 절대 null을 받지 않는 객체를 만들었는데 거기에 Optional을 사용하는 것도 비효율적인 행위입니다.
예를 들면 null을 하용하지 않는 타입을 사용하거나, null을 반환하지 않도록 코드를 구현하면 굳이 Optional을 사용하지 않아도 되는 것이죠.
📌 그럼에도 불구하고 Optional을 쓴다면, 어떻게 써야 하는가?
그럼에도 불구하고 비싼 Optional을 써야 한다면..이왕 쓰는거 잘 써봅시다.
✅ 우선 그냥 값을 얻을 목적이라면 삼항연산자 씁시다.
Optional을 쓰기에 어떠한 값을 비교하기 위한 것이라면 그냥 삼항 연산자를 쓰는게 더 경제적입니다.
return Optional.ofNullable(value).orElse("NULL"); // 💩 return value != null ? value : "NULL"; // 👍
✅ Optional은 클래스의 필드로 사용하지 않아야 합니다.
우선 Optional은 Serializable을 구현하지 않기에 필드로 애시당초 사용하면 안됩니다.
또한 Optional을 사용하게 되면 필드의 값들에 null이 할당되어도 그 위험한 값이 Optional 속으로 숨어버립니다.
이를 그대로 두었다가는 비즈니스 로직에 치명적인 지뢰를 두는 것과 마찬가지인거죠.
✅ 또한 생성자나 메서드의 인자로 사용하지 말아야 합니다.
이는 호출 시 마다 Optional을 생성해서 인자로 전달해주어야 하는데, 굳이 호출하는 쪽에서 Optional을 만들어 넘겨주는 것보다는 호출되는 쪽에서 null 체크를 하는 것이 더욱 안전합니다.
굳이 비싼 Optional을 인자로 사용하지말고 호출되는 쪽에 null 체크의 권한을 위임하는게 좋습니다.
✅ isPresent()나 get()보다는 orElse()나 orElseGet(), orElseThrow()를 씁시다.
이왕 쓰는거 isPresent()로 null 검증을 다시 할 바에는 orElse류의 함수를 써서 한 줄이라도 더 줄입시다.
또한 orElse(new ...) 보다는 orElseGet(() -> new ...)로 바꿔서 씁시다.
OrElse의 경우 값이 있든 없든 무조건 실행이 됩니다.
즉, new 객체를 생성해 새로운 연산을 수행해야 하는 경우에는 orElseGet()을 사용하는 것이 더 좋습니다
그 이유는 orElseGet은 Supplier를 매개변수로 받는데 이는 Optional에 값이 없을 때만 실행되기 때문입니다.
즉, 값이 없을 때만 새로운 객체와 연산을 수행하므로 불필요한 오버헤드를 줄일 수 있습니다.
📌 마치며
그간 이렇게 비싼 Optional을 맹목적으로 굳이(?) 써온 것 같습니다.
NullPointerException을 방지하기 위해, 비즈니스적으로 Null이라는 지뢰를 잘 다루기 위해 Optional을 적극적으로 사용하려 했지만, 이젠 오히려 조금은 지양해야 겠다는 생각이 드네요.
비용 대비 확실한 효용이 있는 포인트에만 사용해겠다는 생각이 듭니다.
큰 깨달음을 주신 분들께 감사드릴 따름입니다.
'스터디 노트' 카테고리의 다른 글
윈도우 10에서 Docker(도커)에 Ubuntu(우분투) 최신 버전 설치하기 (0) 2023.12.13 Apache HttpClient 5 알아보기 (0) 2023.12.06 @Transactional 사용 시 주의해야 할 사항들 (1) 2023.12.04 @Transactional 애너테이션에 대하여 (1) 2023.12.04 Java에서 Serializable은 무엇일까? 직렬화 vs 역직렬화 (1) 2023.12.04