Optional 형식을 통해 도메인 모델의 의미를 명확히 만들고, null 참조 대신 값이 없는 상황을 표현해 보자.
Null 참조의 문제점
에러의 근원 : NullPointerException
코드를 어지럽힘 : null 확인 코드
아무 의미가 없음 : null 은 아무 의미도 표현하지 않는다.
자바 철학에 위배 : 자바는 개발자로부터 모든 포인터를 숨겼지만 null 포인터는 예외
형식 시스템에 구멍을 만듦 : null의 의미를 알 수 없음
java.util.Optional<T>
값이 있을 경우 Optional 클래스는 값을 감싼다.
값이 없으면 Optional.empty
Optional 적용 패턴
Optional 객체 만들기
빈 Optional
Optional<Car> optCar =Optional.empty();
null이 아닌 Optional
Optional<Car> optCar =Optional.of(car);
null 값으로 Optional 만들기
Optional<Car> optCar =Optional.ofNullable(car);
Map으로 Optional 값을 추출하고 변환하기
Optional<Insurance> optInsurance =Optional.ofNullable(insurance);Optional<String> name =optInsurance.map(Insurance::getName);
flatMap으로 Optional 객체 연결
Optional<Person> optPerson =Optional.of(person);Optional<String> name =optPerson.flatMap(Person::getCar).flatMap(Car::getInsurance).map(Insurance::getName).orElse("Unkown");
Optional의 직렬화 불가
Optional은 Serializable Interface를 구현하지 않는다.
Optional 클래스를 필드 형식으로 사용할 수 없으니, Optional 로 값을 반환받을 수 있는 메서드를 추가하자.
int minAge =20;Optional<Person> optPerson =Optional.of(person);//Person이 minAge 이상의 나이일 경우에만 보험회사 이름 반환Optional<String> name =optPerson.filter(p ->p.getAge() >= minAge).flatMap(Person::getCar).flatMap(Car::getInsurance).map(Insurance::getName).orElse("Unkown");
Instant.ofEpochSecond(3);Instant.ofEpochSecond(3,0);Instant.ofEpochSecond(2,1_000_000_000); //1초 후의 나노초Instant.ofEpochSecond(4,-1_000_000_000); //4초 전의 나노초
Period tenDays =Period.between(LocalDate.of(2022,1,1),LocalDate.of(2022,1,11));//시간 객체를 사용하지 않고 생성Period tenDays =Period.ofDays(10);Period threeWeeks =Period.ofWeeks(3);Period twoYearsSixMonthsOneDay =Period.of(2,6,1);
간격을 표현하는 날짜와 시간 클래스의 공통 메서드
- between
- from
- of
- parse
- addTo
- get
- isNegative
- isZero
- minus
- multipliedBy
- negated
- plus
- subtractFrom