Optional을 어떻게 하면 효율적으로 사용할 수 있을까?
전통적인 null check 코드를 살펴보자
NullPointException 방어패턴
- 중첩 null 체크
if(a != null){
B b = a.getMember();
if(b != null){
C c = b.getAddress());
if(c != null){
...
}
}
}
return "incheon";
- return 하기
if(a == null) return "incheon";
B b = a.getMember();
if(b == null) return "incheon";
C c = b.getAddress();
...
어떻게 하면 null처리를 효과적으로 어떻게 할 수 있을까?
Optional
자바8에는 Optional이라는 것이 생겼다.
자바에서는 위에서 봤던것 처럼 null 체크로직 때문에 가독성과 유지보수성이 떨어지는 것을 볼 수 있다.
Optional이란?
Optional이란 존재할 수도 있지만 존재하지 않을 수도 있는 .. 즉, null이 될 수 있는 객체를 감싸고있는 wrapper클래스이다.
Optional 변수 선언하기
java.util.Optional<T>
Optional<Address> address;
Optional<Member> member;
Optional 객체 생성하기
Optional은 세가지 정적팩토리 메서드를 제공한다.
1.Optional.empty() : null을 담고 있는 Optional 객체를 생성
Optional<Address> address = Optional.empty();
2. Optional.of(value) : null이 아닌 객체를 담고 있는 Optional 객체 생성 (null일 경우, NPE 발생)
Optional<Address> address = Optional.of(anotherAddress);
3. Optional.ofNullable(value) : null인지 아닌지 알 수 없는 객체를 담고 있는 Optional 객체 생성 (null 이여도, NPE가 발생하지 않음). null일 경우 Optional.empty()와 같은 null을 담고 있는 Optional 객체를 생성
Optional<Address> address = Optional.ofNullable(anotherAddress);
Optional<Address> address = Optional.ofNullable(null);
Optional객체 접근하기
Optional에 담고 있는 객체가 존재한다면, 아래의 메소드는 모두 객체를 리턴하지만
객체가 존재하지 않을 때 메소드별로 처리하는 방법이 조금씩 다르다.
1. get()
객체가 비어있다면, NoSuchElementException
을 던짐
2. orElse(T other)
객체가 비어있다면, 넘어온 인자(other)를 반환
3. orElseGet(Supplier<? extends T> other)
객체가 비어있다면, Supplier 함수형 인자를 통해 생성된 객체를 반환
4. orElseThrow(Supplier<? extends T> exceptionSupplier)
객체가 비어있다면, Supplier 함수형 인자를 통해 예외를 던짐
Optional 활용하기
Stream클래스가 갖고 있는 map(), flatMap(), filter() 와 같은 메소드를 Optional도 갖고 있다.
이 메소드들을 활용해서 더 세련되게 null check를 할 수 있다.
map()사용하기
위에서 사용한 중첩 null체크 로직을 Optional로 고쳐보자
if(a != null){
B b = a.getMember();
if(b != null){
C c = b.getAddress());
if(c != null){
c.getCity();
}
}
}
return "incheon";
리팩토링 후
return Optional.Nullable(a)
.map(a::getMember())
.map(b::getAddress())
.map(c::getCity())
.orElse("incheon");
Optional의 map()을 사용하면 이렇게 간단하고 가독성 좋게 null-safe한 코드를 작성할 수 있다.
filter() 사용하기
if(member != null & member.getAge() > 30){
return member.getName();
}
리팩토링 후
return Optional.Nullable(member)
.filter(m -> member.getAge() > 30)
.map(Member::getName);
리턴타입은 Optional<String> 이 된다.
리턴값이 Optional이므로 null이 존재할 수 있다는 것을 메소드 사용자에게 알려줄 수 있다.
'프로그래밍 노트 > JAVA' 카테고리의 다른 글
[JAVA] Stream 필터링한 요소 수집(collect()) (0) | 2020.01.07 |
---|---|
[JAVA] Stream 매칭(allMatch(), anyMatch(), noneMatch()) (0) | 2020.01.07 |
[JAVA] LocalDate, LocalDateTime, LocalTime 문자열 파싱(parsing), 포맷팅(Formatting) (0) | 2019.10.23 |
[JAVA] Format 클래스 (0) | 2019.10.23 |
Class 클래스 (0) | 2019.10.21 |