NullPointerException을 피하려면, 대부분 아래와 같이 null 확인 코드를 넣어서 해결하려고 한다.
public String getCarInsurancename(Person person) {
if (person != null) {
Car car = person.getCar();
if (car != null) {
Insurance insurance = car.getInsurance();
if (insurance != null) {
return insurance.getName();
}
}
}
return "Unknown";
}
하지만, 이러한 방식은 코드를 난잡하게 하고 쉽게 파악하기에 어렵다.
Java SE 8에서는 java.util.Optional라는 선택형값을 캡슐화하는 클래스를 제공한다.
값이 있으면 Optional 클래스는 값을 감싸며, 값이 없으면 Optional.empty 메서드로 Optional을 반환한다.
Optional.empty는 Optional의 특별한 Singleton Instance를 반환하는 정적 팩토리 메서드이다.
Method | Description |
---|---|
empty | 빈 Optional 인스턴스 반환 |
of | 값이 존재하면 값을 감싸는 Optional을 반환하고, 값이 null이면 NullPointerException을 발생 |
ofNullable | 값이 존재하면 값을 감싸는 Optional을 반환하고, 값이 null이면 빈 Optional을 반환 |
filter | 값이 존재하며 Predicate와 일치하면 값을 포함하는 Optional을 반환한다. |
값이 없거나 Predicate와 일치하지 않으면 빈 Optional을 반환한다. | |
ifPresent | 값이 존재하면 지정된 Consumer를 실행하고, 값이 없으면 아무것도 안함 |
ifPresentOrElse | 값이 존재하면 지정된 Consumer를 실행하고, 값이 없으면 Runnable을 실행 |
isPresent | 값이 존재하면 true를 반환하고, 값이 없으면 false를 반환 |
map | 값이 존재하면 제공된 매핑 함수를 적용 |
flatMap | 값이 존재하면 인수로 제공된 함수를 적용한 결과 Optional을 반환하고, 값이 없으면 빈 Optional을 반환 |
get | 값이 존재하면 해당 값을 반환하고, 값이 없으면 NoSuchElementExeption을 발생 |
or | 값이 존재하면 같은 Optional을 반환하고, 값이 없으면 Supplier에서 만든 Optional을 반환 |
orElse | 값이 존재하면 값을 반환하고, 값이 없으면 기본값을 반환 |
orElseGet | 값이 존재하면 값을 반환하고, 값이 없으면 Supplier에서 제공하는 값을 반환 |
orElseThrow | 값이 존재하면 값을 반환하고, 값이 없응면 Supplier에서 생성한 예외를 발생 |
stream | 값이 존재하면 존재하는 값만 포함하는 Stream을 반환하고, 값이 없으면 빈 Stream을 반환 |
Optional<Car> optCar = Optional.empty();
Optional<Car> optCar = Optional.of(car);
Optional<Car> optCar = Optional.ofNullable(car);
Optional의 map 메서드로 값을 추출하여 변환할 수 있다.
Optional<Insurance> optInsurance = Optional.ofNullable(insurance);
Optional<String> name = optInsurance.map(Insurance::getName);
Optional 객체를 연결할 때는 Optional의 flatMap 메서드를 사용한다.
public String getCarInsuranceName(Optional<Person> person) {
return person.flatMap(Person::getCar)
.flatMap(Car::getInsurance)
.map(Insurance::getName)
.orElse("Unknown");
}
Java SE 9에서는 Optional에 Stream() 메서드를 추가했다.
public Set<String> getCarInsuranceNames(List<Person> persons) {
return persons.stream()
.map(Person::getCar)
.map(optCar -> optCar.flatMap(Car::getInsurance))
.map(optIns -> optIns.map(Insurance::getName))
.flatMap(Optional::stream)
.collect(toSet());
}
Optional의 filter 메서드로 Predicate가 만족하면 값을 반환하고, 그렇지 않으면 빈 Optional 객체를 반환한다.
optInsurance.filter(insurance -> "CambridgeInsurance".equals(insurance.getName()))
.ifPresent(x -> System.out.println("ok");