Optional(옵셔널)
Optional은 자바 프로그래밍에서 굉장히 자주 보이는 NullPointerException을 방지하기 위해서 등장했다고 볼 수 있다. 자바에서 NullPointerException을 자주 보게 되는 이유가 뭘까? 그 이유는 null을 리턴할 수도 있는 객체를 참조할 때 null 체크를 깜빡했기 때문이다. 우선 다음 코드를 보자.
public class PetStore {
public String getBuyer(Pet pet) {
Master master = pet.getMaster();
return master.getName();
}
}
위 코드에서는 null이 총 세 군데에서 발생할 수 있다. 첫 번째는 pet이 null일 수도 있고, 두 번째는 master가 null일 수도 있고, 마지막으로는 master.getName()이 null일 수도 있다. 자바 8 이전에는 이런 상황에 NullPointerException을 방지하기 위해서는 다음과 같이 코드를 작성했어야 했다.
public class PetStore {
public String getBuyer(Pet pet) {
if (pet == null) {
throw new NullPointerException("Pet doesn't exist!!");
}
Master master = pet.getMaster();
if (master == null) {
throw new NullPointerException("Pet has not yet been sold!!");
}
return master.getName();
}
}
먼저 pet을 체크하고, master를 체크한 뒤, getBuyer() 메서드의 리턴 값을 참조하는 String 객체를 체크해야 된다. Optional을 사용하면 위와 같이 if 문을 많이 사용하는 코드는 작성할 필요가 없어진다. 다음 코드를 보자.
public class PetStore {
public Optional<String> getBuyer(Pet pet) {
return Optional.ofNullable(pet)
.map(Pet::getMaster)
.map(Master::getName);
}
}
Optional을 사용함으로써 지저분한 if 문들이 필요 없게 되었다. Optional은 값 한 개가 들어 있을 수도 있고, 없을 수도 있는 컨테이너이다. Optional을 사용할 때는 다음과 같은 주의사항이 있다.
- 리턴 값으로만 쓰기를 권장한다.(파라미터, 맵의 키, 객체 필드로는 쓰지 말자.)
- Optional을 리턴하는 메서드에서 null을 리턴하지 말자.
- 기본형 Optional은 따로 있다. OptionalInt, OptionalLong 등...
- Collection, Map, Stream Array, Optional은 웬만하면 Optional로 감싸지 말자.
Optional API
Optional API의 종류에 대해서 기능별로 살펴보자.
Optional 만들기
- Optional.of() : 파라미터를 Optional로 감싸서 리턴하고 파라미터가 null이면 NullPointerException을 던진다.
- Optional.ofNullable() : 파라미터를 Optional로 감싸서 리턴하고 파라미터가 null이면 빈 Optional을 리턴한다.
- Optional.empty() : 빈 Optional을 리턴한다.
Optional에 값이 있는지 확인하기
- isPresent() : 값이 있는지 확인한다.
- isEmpty() : 빈 값인지 확인한다.(자바 11부터)
Optional에 있는 값 가져오기
- get() : 값을 가져오고 값이 null이라면 NoSuchElementException을 던진다.
- orElse(T) : 값이 있다면 가져오고 값이 null이라면 파라미터를 리턴한다.
- orElseGet(Supplier) : 값이 있다면 가져오고 없다면 내부적으로 Supplier.get() 메서드를 호출한다.
- orElseThrow(Supplier) : 값이 있다면 가져오고 없다면 내부적으로 Supplier.get() 메서드를 던진다.
Optional에 값이 있는 경우 사용하기
- ifPresent(Consumer) : 값이 null이 아니라면 내부적으로 Consumer.accept() 메서드를 호출한다.
Optional에 들어 있는 값 걸러내기
- Optional filter(Predicate) : Stream과 마찬가지로 특정 조건으로 걸러낼 때 쓰인다.
Optional에 들어 있는 값 변환하기
- map(Function) : 내부적으로 Function.apply() 메서드를 호출해 값을 변환한다.
- flatMap(Function) : map()과 거의 동일하나, 중첩된 Optional을 단일 요소로 변환한다.
Reference
'Java' 카테고리의 다른 글
| [Java] Java 8의 특징(6) - CompletableFuture (0) | 2022.02.28 |
|---|---|
| [Java] Java 8의 특징(5) - Date와 Time (0) | 2022.02.26 |
| [Java] Java 8의 특징(3) - Stream (0) | 2022.02.23 |
| [Java] Java 8의 특징(2) - 기본 메서드와 스태틱 메서드 (0) | 2022.02.22 |
| [Java] Java 8의 특징(1) - 함수형 인터페이스와 람다 (0) | 2022.02.21 |