////
Search
⚠️

8장 null? 대신 Optional 클래스

우리는 java 프로그램을 작성하는 도중 남녀노소를 가리지 않고 가장 많이 만나는 오류가 있다. 그것은 NullPointerException이다. 또한 null을 만든 사람도 null이 실수라고 이야기한다. 그럼 우리는 null을 어떻게 회피해야 할까? 이를 이번 장에서 알아볼 것이다.
1.
null 참조의 문제점과 null을 멀리해야하는 이유?
2.
null 대신 Optional : null로 부터 안전한 도메인 모델 재구현하기
3.
Optional 활용 : null 확인 코드 제거하기
4.
Optional에 저장된 값을 확인하는 방법
5.
값이 없을 수도 있는 상황을 고려하는 프로그래밍
null... 우리를 가장 많이 괴롭히는 단어이다. NullPointerException은 어떻게 하더라도 검증이 필요했고 이러한 귀찮은 작업을 필자는 매일매일 프로그램을 작성할때 빼먹지 않는 작업으로 했다. 그렇다면 null은 어떤 상황에서 발생하고 null을 피해야하는 이유는 무엇일까?

null 참조의 문제와 null을 멀리해야 하는 이유

null은 왜 발생할까?
값이 없는 상황을 어떻게 처리해야할까? 보수적인 자세로 NullPointerException 줄이기

null 이 주는 문제들

에러의 근원이다 : 자바에서 가장 흔한 가장 많이 발생하는 에러이다.
코드를 어지럽힌다 : 때로는 중첩된 null 확인 코드를 추가해야 하므로 null 때문에 코드의 가독성이 떨어진다.
아무 의미가 없다 : null은 아무런 의미도 표현하지 않는다. 특히 정적 형식 언어에서 값이 없음을 표현하는 방법으로는 적절하지 않다.
자바 철학에 위배된다 : 자바는 개발자로부터 모든 포인터를 숨겼다. 하지만 그 예외가 null이다.
형식 시스템에 구멍을 만든다 : null은 무형식이며 정보를 포함하고 있지 않으므로 모든 참조 형식에 null을 할당할 수 있다. 이런 식으로 null이 할당되기 시작하면서 시스템의 다른 부분으로 null이 퍼졌을 때 애초에 null이 어떤 의미로 사용되었는지 알 수 없다.

null 대신 Optional 클래스

자바는 java.util.Optinal<T> 라는 새로운 클래스를 제공한다. 이는 선택형값을 캡슐화하는 클래스이다. 예를 들자면 어떤 사람이 차를 소유하고 있지 않다면 Person 클래스의 car 변수는 null을 가져야 할 것이다. 하지만 새로운 Optional을 이용할 수 있으므로 null이 할당되는 것이 아니라 변수형을 Optional<Car>로 설정할 수 있다.
값이 있으면 Optional클래스는 값을 감싼다. 하지만 값이 없으면 Optional.empty 메서드로 Optional을 반환한다. Optional.empty는 Optional의 특별한 싱글턴 인스턴스를 반환하는 정적 팩토리 메서드다. null 참조와 Optional.empty()의 차이점은 null을 참조하려 하면 NullPointerException 이 발생하지만 Optional.empty()는 Optional 객체이므로 이를 다양한 방식으로 활용할 수 있다.
값이 없는 상황에서 Optional의 활용

Opional의 활용과 Optional에서 저장된 값 확인하는 방법

optional 적용 패턴

Optional 객체 만들기
맵 메서드로 Optional의 값을 추출하고 변환하기
flatMap으로 Optional 객체 연결
Optional로 자동차의 보험 이름 찾기
도메인 모델에 Optional을 사용했을 때 데이터를 직렬화 할 수 없는 이유? Optional은 "있을 수도 없을 수도" 여부를 구체적으로 표현할 수 있었다. 놀랍게도 Optional 클래스의 설계자는 이와는 다른 용도로만 Optional 클래스를 사용할 것을 가정했다. (Optional의 용도가 선택형 반환값을 지원하는 것 이라고 못박았다.) 즉, Optional 클래스는 필드 형식으로 사용할 것을 가정하지 않았으므로 Serializable 인터페이스를 구현하지 않는다. 따라서 우리 도메인 모델에 Optional을 때려박는다면 직렬화 모델을 사용하는 도구나 프레임워크에 장애가 발생할 수 있다. 이와 같은 단점에도 불구하고 여전히 Optional을 사용해서 도메인 모델을 구성하는 것이 바람직하다고 생각한다.(왜지? 조금 생각해보니 json은 optional을 직렬화할 수 있을까?) 특히 객체 그래프에서 일부 또는 전체 객체가 null 일 수 있는 상황이라면 더더욱 그렇다. 직렬화 모델이 필요하다면 다음과 같이 메서드를 추가하는 방식을 권장한다. json은 직렬화가 가능할까? https://www.baeldung.com/jackson-optional 가능
class Person{ private Car car; public Optional<Car> getCarAsOptional(){ return Optional.ofNullable(car); } }
Java
복사
Optional 스트림 조작 (자바 버전 9)
디폴트 액션과 Optional 언랩
두 Optional 합치기
필터로 특정 값 거르기
Search
메서드
값 존재
값 없음
값 존재 유무 관계없음
Predicate 와 일치할 경우 값을 포함하는 Optional 반환
predicate 와 일치하지 않을 경우 빈 Optional 반환
인수로 제공된 함수를 적용한 결과 Optional 반환
빈 Optional 반환
Optional이 감싸는 값 반환
NoSuchElementException 발생
지정된 Consumer를 실행
지정된 Consumer를 실행
true 반환
false 반환
제공된 함수를 적용 후 Optional로 감싼 결과 반환
빈 Optional 반환
값을 감싸는 Optional 반환
NullPointerException 발생
값을 감싸는 Optional 반환
빈 Optional 반환
같은 Optional 반환
Supplier에서 만든 Optional 반환
받은 값을 반환
설정된 기본 값 반환
받은 값을 반환
Supplier에서 제공하는 값을 반환
받은 값을 반환
Supplier에서 생성한 예외 발생
존재하는 값만 포함하는 스트림 반환
빈 스트림 반환

값이 없을 수도 있는 상황에서 프로그래밍 방법

지금까지 배운 것처럼 새 Optional 클래스를 효과적으로 이용하려면 잠재적으로 존재하지 않는 값의 처리 방법을 바꿔야한다. 즉, 코드 구현만 바꾸는 것이 아니라 네이티브 자바 API와 상호작용하는 방식으로 바꿔야한다.
잠재적으로 null이 될 수 있는 대상 Optional로 감싸기
예외와 Optional 클래스 (책 내용에 이상한 부분이 존재한다.)
기본형 Optional을 사용하지 말아야 하는 이유
응용
결론
역사적으로 프로그래밍 언어에서는 null 참조로 값이 없는 상황을 표현해 왔다.
자바 8에서는 값이 있거나 없음을 표현할 수 있는 java.util.Optional<T>를 제공한다.
Optional은 위의 표에서 알 수 있는 메서드를 이용하여 Optional을 만들 수 있다.
Optional 클래스는 Stream에서 제공되는 비슷한 메서드가 존재한다.
Optional로 값이 없는 상황을 적절하게 처리하도록 강제할 수 있다. 즉, Optional은 예상치 못한 null을 예외를 방지할 수 있다.
Optional 기본 특화형은 안쓰는게 좋다.
Optional의 가장 큰 장점은 "있을 수도 없을 수도" 있는 값을 예측할 수 있다.