[Java] Optional

윤경·2021년 12월 23일
0

Java

목록 보기
9/10

Optional 의도

...
라이브러리 메소드가 반환할 결과값이 '없음'을 명백하게 표현할 필요가 있는 곳에서 제한적으로 사용할 수 있는 메커니즘을 제공하는 것이 `Optional`을 만든 의도였다.

라고한다.

즉, 간단하게 말해 반환값이 "없음"을 나타내는 것이 주목적이다.

공식문서

API Note:
메소드가 반환할 결과값이 '없음'을 명백하게 표현할 필요가 있고, null을 반환하면 에러를 유발할 가능성이 높은 상황에서 메소드의 반환 타입으로 Optional을 사용하자는 것이 Optional을 만든 주 목적이다.

Optional 타입의 변수 값은 절대 null이 되어서는 안되며, 항상 Optional 인스턴스를 가리켜야 한다.

`
결국 사람들이 기대하는 목적과는 다른 목적으로 만들어진 것이다. 그래서 주의사항이 26가지나 된다고 한다.

Optional 사용 시 무심결에 잘못 사용하는 안티 패턴과 올바른 사용법을 자바8 기준으로 정리하자.


1.

➡️ isPresent()-get() 대신 orElse() / orElseGet() / orElseThrow()을 사용하기

2.

➡️ orElse(new ...) 대신 orElseGet(()->new ...) 사용하기

orElse(...)에서 ...는 Optional에 값의 유무에 상관 없이 무조건 실행된다.

따라서 ...새로운 객체를 생성하거나 새로운 연산을 수행하는 경우에는 orElse() 대신 orElseGet()을 사용해야 한다.

Optional에 값이 없으면 orElse()의 인자로써 실행된 값이 반환되므로 실행한 의미가 있지만,
Optional에 값이 있으면 orElse()의 인자로써 실행된 값이 무시되고 버려진다.

따라서 orElse(...)...새 객체 생성이나 새로운 연산을 유발하지 않고 이미 생성되었거나 이미 계산된 값일 때만 사용해야 한다.

정리하자면

  • orElse(): Null인지 아닌지 관계없이 항상 불림
  • orElseGet(): Null일 때만 불림

3.

➡️ 단지 값을 얻을 목적이라면 Optional 대신 null 비교 사용하기

Optional은 비싸기 때문에 단순히 값 또는 null을 얻는 것이 목적이라면 Optional 대신 null 비교를 사용하는 것이 좋다.

4.

➡️ Optional 대신 비어있는 컬렉션 반환하기

말했듯 Optional은 비싸다.

그리고 컬렉션은 null이 아니라 비어있는 컬렉션을 반환하는 것이 좋을 때가 많다.
따라서 컬렉션은 Optional로 감싸서 반환하지 말고 비어있는 컬렉션을 반환해야 한다.

또한, Spring Data JPA Repository 메소드 선언 시 컬렉션을 Optional로 감싸 반환하는 것은 좋지 않다.
컬렉션을 반환하는 Spring Data JPA Repository 메소드는 null을 반환하지 않고 비어있는 컬렉션을 반환하므로 Optional로 감싸 반환할 필요가 없다.

5.

➡️ Optional을 필드로 사용 금지

Optional은 필드에 사용할 목적으로 만들어지지 않았으며, Serializable을 구현하지 않았다.
따라서 필드로 사용하면 안된다.

6.

➡️ Optional을 생성자나 메소드 인자로 사용 금지

Optional을 생성자나 메소드 인자로 사용하면 호출할 때마다 Optional을 생성해서 인자로 전달해줘야 한다.
하지만 호출되는 쪽 (api나 라이브러리 메소드)에서는 인자가 Optional이든 아니든 null 체크를 하는 것이 언제나 안전하다.

따라서 굳이 비싼 Optional을 인자로 사용하지 말고 호출되는 쪽에 null 체크 책임을 남겨두는 것이 좋다.

7.

➡️ Optional을 컬렉션의 원소로 사용 금지

컬렉션에는 많은 원소가 들어갈 수 있다.
따라서 비싼 Optional을 원소로 사용하지 말고 원소를 꺼낼 때나 사용할 때 null을 체크하는 것이 좋다.

특히 Map은 getOrDefault(), putIfAbsent(), computeIfAbsent(), computeIfPresent() 처럼 null 체크가 포함된 메소드를 제공한다.
그러므로 Map의 원소로 Optional을 사용하지 말고 Map이 제공하는 메소드를 활용하는 것이 좋다.

8.

➡️ of(), ofNullable() 혼동 주의하기

of(X)는 X가 null이 아님이 확실할 때만 사용해야 한다.
X가 null이면 NullPointerException이 발생한다.

ofNullable(X)은 X가 null일 수도 있을 때만 사용해야 한다.
X가 null이 아님이 확실하면 of(X)를 사용해야 한다.

9.

➡️ Optional<T> 대신 OptionalInt, OptionalLong, OptionalDouble 사용하기

optional에 담길 값이 int, long, double이라면 Boxing/Unboxing이 발생하는
Optional<Integer>, Optional<Long>, Optional<Double>을 사용하지 말고,
OptionalInt, OptionalLong, OptionalDouble를 사용해야 한다.


정리

  1. isPresent()-get() 대신 orElse() / orElseGet() / orElseThrow()을 사용하기
  1. orElse(new ...) 대신 orElseGet(()->new ...) 사용하기
  1. 단지 값을 얻을 목적이라면 Optional 대신 null 비교 사용하기
  1. Optional 대신 비어있는 컬렉션 반환하기
  1. Optional을 필드로 사용 금지
  1. Optional을 생성자나 메소드 인자로 사용 금지
  1. Optional을 컬렉션의 원소로 사용 금지
  1. of(), ofNullable() 혼동 주의하기
  1. Optional<T> 대신 OptionalInt, OptionalLong, OptionalDouble 사용하기

참고

profile
개발 바보 이사 중

0개의 댓글