프로그래밍 노트/JAVA

[JAVA] Optional 사용해서 null-safety한 코드짜기

깡냉쓰 2019. 11. 25. 22:54
728x90
반응형

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이 존재할 수 있다는 것을 메소드 사용자에게 알려줄 수 있다.

참고블로그)https://www.daleseo.com/java8-optional-before/

728x90
반응형