Optional 를 쓰는 이유
- 메소드의 시그니처만 보고도 선택형 값을 기대해야하는지 판단 가능
- null 에 의한 null pointer exception 발생에 대한 해결책으로 등장
Optional.empty()와 null의 차이
- Optional.empty() : Optional의 싱글턴 인스턴스를 반환하는 정적 팩토리 메서드를 통해 생성됨. 객체 그 자체
- null : 참조하면 Null Pointer Exception 이 발생
Optional.of() 와 Optional.ofNullable() 차이
- Optional.of(some) : some 이 null이라면 npe가 발생한다.
- Optional.ofNullable(some) : some이 null이라면 Optional 객체를 만든다.
도메인 모델에 Optional를 사용했을 때 데이터를 직렬화할 수 없다!
- 필드 형식으로 사용되는 것은 설계자가 권장하지 않는 사항 - Optional 클래스는 Serializable 인터페이스를 구현하지 않았기 때문에 직렬화 모델에서 문제가 생길 수 있다
- 직렬화 모델이 필요하다면 다음 처럼 Optional 로 값을 반환할 수 있는 메서드를 추가하는게 바람직하다
public class Person {
private Car car;
public Optional<Car> getCarAsOptional() {
return Optional.ofNullable();
}
}
Optional 스트림 조작 : Optional.stream() 사용하기
/**
* If a value is present, returns a sequential {@link Stream} containing
* only that value, otherwise returns an empty {@code Stream}.
*
* @apiNote
* This method can be used to transform a {@code Stream} of optional
* elements to a {@code Stream} of present value elements:
* <pre>{@code
* Stream<Optional<T>> os = ..
* Stream<T> s = os.flatMap(Optional::stream)
* }</pre>
*
* @return the optional value as a {@code Stream}
* @since 9
*/
public Stream<T> stream() {
if (!isPresent()) {
return Stream.empty();
} else {
return Stream.of(value);
}
}
// 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))
.flagMap(Optional::stream)
.collect(toSet());
}
// Optional.stream() 를 안쓴다면 filter를 써야함
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))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(toSet());
}
Optional.stream() 은 Optional의 값이 없다면 빈 stream를 반환하고 그게 아니라면 값이 들어간 Stream를 반환한다. 이 메소드를 통해 비어있는 Optional를 필터링하고 처리할 수 있다.
두 Optional 합치기
수정 전
public Optional<Insurance> nullSafeFindCheapestInsurance(
Optional<Person> person,
Optional<Car> car
) {
if(person.isPresent() && car.isPresent()) {
return Optional.of(findCheapestInsurance(person.get(), car.get());
}
}
Optional에서 해결하고자 했던 null 확인 조건 분기와 다를 바 없다.
수정 후
public Optional<Insurance> nullSafeFindCheapestInsurance(
Optional<Person> person,
Optional<Car> car
) {
return person.flatMap(p -> car.map(c -> findCheapestInsurance(p, c));
}
'📗Java' 카테고리의 다른 글
[Java] Virtual Thread 알아보기 (0) | 2024.05.23 |
---|---|
[Java] Arrays.sort() 어떤 정렬 알고리즘을 쓸까? (2) | 2024.04.30 |
[Java] Reflection API (5) | 2023.09.24 |
[모던자바인액션] 람다 표현식 (1) | 2023.09.14 |
[모던자바인액션] 동작 파라미터화 코드 전달하기 (0) | 2023.09.11 |