Optional
Optional
Java에서는 Optional
Optional
Optional 활용하기
-
Optional 생성
public static void main(String[] args) { Optional<Integer> integer = Optional.of(10); Optional<Integer> integerOptional = Optional.ofNullable((Math.random() * 10) > 5 ? null : 1); Optional<Object> empty = Optional.empty(); }-
Optional.of(10)
값이 10인 Optional 객체를 만듭니다. 안의 객체로 들어갈 값은 null을 고려하지 않습니다.만일, null 값이 들어간다면 NullPointException이 발생한다
-
Optional.ofNullable((Math.random() * 10) > 5 ? null : 1);
0~9까지의 실수가 5보다 클 경우 null을 아닐경우 1을 인자값으로 Optional을 만듭니다. 이처럼 값이 null일수도 있을 경우 o
f는 에러를 발생하기 때문에 ofNullable()을 사용한다.
-
Optional.empty()
내부값이 비어있는 Optional을 반환합니다. 주로 반환값이 null일 때 사용한다.
-
-
Optional에 값이 있는지 없는지 확인하기
-
.isPresent()
포장된 값이 null 이 아니면 True 를 반납한다.
-
.isEmpty()
isEmpty() 로 null 인 경우 true 를 얻을 수 있다.
-
-
Optional에 있는 값 가져오기
public static void main(String[] args) {
Optional<Integer> integer = Optional.ofNullable(10);
Optional<Object> empty = Optional.empty();
System.out.println(integer.get());
integer.ifPresent(System.out::println);
integer.orElse(testInteger());
// 포장값이 Null 이 아닌 경우에도 default 객체를 생성한다. "create integer test" 수행
integer.orElseGet(App::testInteger);
// 포장값이 Null 이 아닌 경우 호출되지 않는다. 수행X
integer.orElseThrow(NoSuchElementException::new);
}
public static Integer testInteger(){
System.out.println("create integer test");
return (int)(Math.random() * 10);
}
-
Get()
-
내부가 null인 경우를 고려할경우
-
ifPresent :Optional에 값이 있는 경우 그 값을 Consumer Functional Interface에 전달 후 로직을 수행.
-
orElse: 이 있는 경우 가져오고 없는 경우 인자값으로 선언한 내용을 반환한다.
-
orElseGet : 값이 있으면 가져오고 없는 경우에 Supplier Functional Interface로직을 수행한다.
-
orElseThrow : 값이 있으면 가져오고 없으면 에러를 던진다.
-
-
내부 값을 걸러내서 가져오기
- Optional.filter(Predicate) : Predicate Functional Interface를 수행 하여 조건에 부합하는 값을 가져온다.
-
내부값 변환하기
-
Optional map(Function) : Function Functional Interface를 수행하여 내부 값을 순회하며 변경한 후 반환한다.
-
Optional flatMap(Function) :Optional 안에 들어있는 인스턴스가 Optional인 경우 내부 원소값을 꺼낼 때 사용한다.
-
Optional 사용 가이드
[ Optional이 위험한 이유, Optional을 올바르게 사용해야 하는 이유 ]
Optional을 사용하면 코드가 Null-Safe해지고, 가독성이 좋아지며 애플리케이션이 안정적이 된다는 등과 같은 얘기들을 많이 접할 수 있
다. 하지만 이는 Optional을 목적에 맞게 올바르게 사용했을 때의 이야기이고, Optional을 남발하는 코드는 오히려 다음과 같은 부작용
(Side-Effect)를 유발할 수 있다.
-
NullPointerException 대신 NoSuchElementException가 발생함
-
이전에는 없었던 새로운 문제들이 발생함
-
코드의 가독성을 떨어뜨림
-
시간적, 공간적 비용(또는 오버헤드)이 증가함
[ 올바른 Optional 사용법 가이드 ]
-
Optional 변수에 Null을 할당하지 말아라
empty()를 사용 값을 초기화하여 사용하는것을 권장
-
값이 없을 때 Optional.orElseX()로 기본 값을 반환하라
-
단순히 값을 얻으려는 목적으로만 Optional을 사용하지 마라
// AVOID public String findUserName(long id) { String name = ... ; return Optional.ofNullable(name).orElse("Default"); } // PREFER public String findUserName(long id) { String name = ... ; return name == null ? "Default" : name; } -
생성자, 수정자, 메소드 파라미터 등으로 Optional을 넘기지 마라
// AVOID public class User { private final String name; private final Optional<String> postcode; public Customer(String name, Optional<String> postcode) { this.name = Objects.requireNonNull(name, () -> "Cannot be null"); this.postcode = postcode; } public Optional<String> getName() { return Optional.ofNullable(name); } public Optional<String> getPostcode() { return postcode; } }Optional은 반환 타입으로 대체 동작을 사용하기 위해 고안된 것임을 명심
-
Collection의 경우 Optional이 아닌 빈 Collection을 사용하라
// AVOID public Optional<List<User>> getUserList() { List<User> userList = ...; // null이 올 수 있음 return Optional.ofNullable(items); } // PREFER public List<User> getUserList() { List<User> userList = ...; // null이 올 수 있음 return items == null ? Collections.emptyList() : userList; } -
반환 타입으로만 사용하라
Optional은 반환 타입으로써 에러가 발생할 수 있는 경우에 결과 없음을 명확히 드러내기 위해 만들어졌으며, Stream API와 결합되
어 유연한 체이닝 api를 만들기 위해 탄생한 것이다
참고
https://mangkyu.tistory.com/70
https://catsbi.oopy.io/81ee5bdc-6825-46f8-b1d2-c608ab2d6465#e7dc4d5a-6af4-4f3b-9e4c-16794c2f0514