Optional
의도...
라이브러리 메소드가 반환할 결과값이 '없음'을 명백하게 표현할 필요가 있는 곳에서 제한적으로 사용할 수 있는 메커니즘을 제공하는 것이 `Optional`을 만든 의도였다.
라고한다.
즉, 간단하게 말해 반환값이 "없음"을 나타내는 것이 주목적이다.
API Note:
메소드가 반환할 결과값이 '없음'을 명백하게 표현할 필요가 있고, null을 반환하면 에러를 유발할 가능성이 높은 상황에서 메소드의 반환 타입으로 Optional을 사용하자는 것이 Optional을 만든 주 목적이다.
Optional 타입의 변수 값은 절대 null이 되어서는 안되며, 항상 Optional 인스턴스를 가리켜야 한다.
`
결국 사람들이 기대하는 목적과는 다른 목적으로 만들어진 것이다. 그래서 주의사항이 26가지나 된다고 한다.
Optional 사용 시 무심결에 잘못 사용하는 안티 패턴과 올바른 사용법을 자바8 기준으로 정리하자.
➡️ isPresent()-get()
대신 orElse()
/ orElseGet()
/ orElseThrow()
을 사용하기
➡️ orElse(new ...)
대신 orElseGet(()->new ...)
사용하기
orElse(...)
에서 ...
는 Optional에 값의 유무에 상관 없이 무조건 실행된다.
따라서 ...
가 새로운 객체를 생성하거나 새로운 연산을 수행하는 경우에는 orElse()
대신 orElseGet()
을 사용해야 한다.
Optional에 값이 없으면 orElse()
의 인자로써 실행된 값이 반환되므로 실행한 의미가 있지만,
Optional에 값이 있으면 orElse()
의 인자로써 실행된 값이 무시되고 버려진다.
따라서 orElse(...)
는 ...
가 새 객체 생성이나 새로운 연산을 유발하지 않고 이미 생성되었거나 이미 계산된 값일 때만 사용해야 한다.
정리하자면
orElse()
: Null인지 아닌지 관계없이 항상 불림orElseGet()
: Null일 때만 불림
➡️ 단지 값을 얻을 목적이라면 Optional
대신 null
비교 사용하기
Optional
은 비싸기 때문에 단순히 값 또는 null
을 얻는 것이 목적이라면 Optional
대신 null
비교를 사용하는 것이 좋다.
➡️ Optional
대신 비어있는 컬렉션 반환하기
말했듯 Optional
은 비싸다.
그리고 컬렉션은 null
이 아니라 비어있는 컬렉션을 반환하는 것이 좋을 때가 많다.
따라서 컬렉션은 Optional
로 감싸서 반환하지 말고 비어있는 컬렉션을 반환해야 한다.
또한, Spring Data JPA Repository 메소드 선언 시 컬렉션을 Optional
로 감싸 반환하는 것은 좋지 않다.
컬렉션을 반환하는 Spring Data JPA Repository 메소드는 null
을 반환하지 않고 비어있는 컬렉션을 반환하므로 Optional
로 감싸 반환할 필요가 없다.
➡️ Optional
을 필드로 사용 금지
Optional
은 필드에 사용할 목적으로 만들어지지 않았으며, Serializable
을 구현하지 않았다.
따라서 필드로 사용하면 안된다.
➡️ Optional
을 생성자나 메소드 인자로 사용 금지
Optional
을 생성자나 메소드 인자로 사용하면 호출할 때마다 Optional
을 생성해서 인자로 전달해줘야 한다.
하지만 호출되는 쪽 (api나 라이브러리 메소드)에서는 인자가 Optional
이든 아니든 null
체크를 하는 것이 언제나 안전하다.
따라서 굳이 비싼 Optional
을 인자로 사용하지 말고 호출되는 쪽에 null
체크 책임을 남겨두는 것이 좋다.
➡️ Optional
을 컬렉션의 원소로 사용 금지
컬렉션에는 많은 원소가 들어갈 수 있다.
따라서 비싼 Optional
을 원소로 사용하지 말고 원소를 꺼낼 때나 사용할 때 null
을 체크하는 것이 좋다.
특히 Map은 getOrDefault()
, putIfAbsent()
, computeIfAbsent()
, computeIfPresent()
처럼 null
체크가 포함된 메소드를 제공한다.
그러므로 Map의 원소로 Optional
을 사용하지 말고 Map이 제공하는 메소드를 활용하는 것이 좋다.
➡️ of()
, ofNullable()
혼동 주의하기
of(X)
는 X가 null이 아님이 확실할 때만 사용해야 한다.
X가 null이면 NullPointerException
이 발생한다.
ofNullable(X)
은 X가 null일 수도 있을 때만 사용해야 한다.
X가 null이 아님이 확실하면 of(X)
를 사용해야 한다.
➡️ Optional<T>
대신 OptionalInt
, OptionalLong
, OptionalDouble
사용하기
optional에 담길 값이 int, long, double이라면 Boxing/Unboxing이 발생하는
Optional<Integer>
, Optional<Long>
, Optional<Double>
을 사용하지 말고,
OptionalInt
, OptionalLong
, OptionalDouble
를 사용해야 한다.
isPresent()-get()
대신orElse()
/orElseGet()
/orElseThrow()
을 사용하기
orElse(new ...)
대신orElseGet(()->new ...)
사용하기
- 단지 값을 얻을 목적이라면
Optional
대신null
비교 사용하기
Optional
대신 비어있는 컬렉션 반환하기
Optional
을 필드로 사용 금지
Optional
을 생성자나 메소드 인자로 사용 금지
Optional
을 컬렉션의 원소로 사용 금지
of()
,ofNullable()
혼동 주의하기
Optional<T>
대신OptionalInt
,OptionalLong
,OptionalDouble
사용하기