728x90
반응형
SMALL
Goal: optional을 사용하기 전 개념을 확실하게 알고 써야할 것 같아 모던 자바 인 액션을 읽고 정리
null 참조 역사
- 자바 포함 최근 수십 년 탄생한 대부분 언어 설계에는 null 참조 개념 포함
- 함수형 언어인 하스켈, ML 등을 예외적으로 null 참조 개념을 사용하지 않는 언어
- 대수적 데이터 형식 포함
- 데이터 형식을 간결하게 표현할 뿐만 아니라 null 같은 특별한 값을 포함할 것인지 등을 명시하는 규격 명세 포함
- 대수적 데이터 형식 포함
11. 1 값이 없는 상황 처리
11.1.1 보수적인 자세로 NullPointerException 줄이기
예제 11-2
문제점
- 변수 접근 시마다 중첩된 if 추가
- 코드 들여쓰기 수준 증가
→ 깊은 의심(deep doubt) (= 반복 패턴(recurring pattern))
예제 11-3
문제점
- 중첩 if 블록 제거, 즉시 return “Unknow” 반환
→ 너무 많은 출구 - 유지보수 어려움
11.1.2 null 때문에 발생하는 문제
자바에서 null 참조를 사용하면서 발생할 수 있는 이론적, 실용적 문제
- 에러의 근원
- 코드를 어지럽힘
- 아무 의미가 없음
- 자바 철학에 위배
- 자바는 개발자로부터 모든 포인터를 숨김
- but 예외가 있는 것이 null 포인터
- 형식 시스템에 구멍을 만듦
11.1.3 다른 언어에서 null 대신 사용하는 것
- 그루비
- 안전 내비게이션 연산자
- 하스켈
- 선택형값(optional value)을 저장할 수 있는 Maybe라는 형식 제공
- 스칼라
- T형식의 값을 갖거나 아무 값도 갖지 않을 수 있는 Optiona[T]라는 구조 제공
11. 2 Optional 클래스 소개
자바 8 - java.util.Optional<T>
Optional
- 선택형값을 캡슐화하는 클래스
- 값이 있으면 값을 감쌈
- 값이 없으면 Optional.empty 메서드로 Optional 반환
- Optional의 특별한 싱글턴 인스턴스를 반환하는 정적 팩토리 메서드
Optional.empty()와 null 참조 차이
- null 참조 - NullPointerException 발생
- Optional.empty()는 Optional 객체이므로 이를 다양한 방식으로 활용
null → Optional 사용
- null 참조 대신 값이 없을 수 있음 명시적으로 표시
public class Person {
private Optional<Car> car; // 사람이 차를 소유했을 수도, 소유하지 않았을 수도 있으므로 Optional로 정의
public Optional<Car> getCar() {
return car;
}
public class Car {
private Optional<Insurance> insurance; // 자동차가 보험에 가입되어 있을 수도, 가입되어 있지 않았을 수도 있으므로 Optional로 정의
public Optional<Insurance> getInsurance() {
return insurance;
}
}
public class Insurance {
private String name; // 보험회사에는 이름이 반드시 있음
public String getName() {
return name;
}
}
}
- 도메인 모델의 의미가 더 명확해짐 - 있을 수도 아닐 수도 있음을 명확히 설명
- 값이 없는 상황이 우리 데이터에 문제가 있는 것인지 아니면 알고리즘의 버그인지 명확하게 구분 가능
- Optional이 등장하면 이를 언랩해서 값이 없을 수 있는 상황에 적절하게 대응하도록 강제하는 효과
11.3 Optional 적용 패턴
- 실제 사용
11.3.1 Optional 객체 만들기
- 빈 Optional
- 정적 팩토리 메서드 Optional.empty()
Optional<Car> optCar = Optional.empty(); - null이 아닌 값으로 Optional 만들기
- 정적 팩토리 메서드 Optional.of로 null이 아닌 값을 포함하는 Optional
Optional<Car> optCar = Optional.of(car);- car가 null이라면 즉시 NullPotinterException 발생
- Optional을 사용하지 않았다면 car의 프로퍼티에 접근하려 할 때 에러가 발생했을 것
- null값으로 Optional 만들기
- 정적 팩토리 메서드 Optional.ofNullable로 null 값을 저장할 수 있는 Optional을 만듦
Optional<Car> optCar = Optional.ofNullable(car);
Optional이 비어있으면 get을 호출했을 때 예외 발생
→ Optional로 명시적인 검사를 제거할 수 있는 방법
Optional에서 제공하는 기능이 스트림 연산에서 영감을 받았음
11.3.2 맵으로 Optional의 값을 추출하고 변환하기
- Optional은 map 메서드 지원
- 스트림의 map - 스트림의 각 요소에 제공된 함수를 적용하는 연산
-
Optional<Insurance> optInsurance = Optional.ofNullable(insurance); Optional<String> name = optInsurance.map(Insurance::getName); - 스트림과 Optional의 map 메서드 비교
11.3.3 flatMap으로 Optional 객체 연결
- map으로 코드 재구현
- 위 코드 컴파일되지 않음 - getInsurance는 또 다른 Optional 객체를 반환하므로 getInsurance 메서드를 지원하지 않음
- 스트림의 flatMap - 함수를 인수로 받아서 다른 스트림을 반환하는 메서드
- 인수로 받은 함수를 적용해서 생성된 각각의 스트림에서 콘텐츠만 남김
- 이차원 Optional을 일차원 Optional로 평준화해야 됨
- flatMap 메서드 덕분에 이차원 Optional이 하나의 삼각형을 포함하는 하나의 Optional로 바뀜
- → 함수를 적용해서 생성된 모든 스트림이 하나의 스트림으로 병합되어 평준화됨
-
Optional<Person> optPerson = Optional.of(person); Optional<String> name = optPerson.map(Person::getCar) .map(Car::getInsurance) .map(Insurance::getName);
- 인수로 받은 함수를 적용해서 생성된 각각의 스트림에서 콘텐츠만 남김
728x90
반응형
LIST
댓글