본문 바로가기

연재작/프로그래밍 언어

Java - Optional 뽀개기 (1)

Optional이란?

 

모나드 패턴을 사용해서 값을 상태로 래핑한 객체이다.

Optional의 가장 큰 특징이자 장점은 Null을 처리하는 과정에 있다.

 

어떤 값을 받고, 이에 대해 처리하고 싶을 때 해당하는 값으로 Null을 받는 경우가 있다.

그렇기 때문에 Null 이 될 수 있다면 기존의 방식은 if문을 사용한 분기처리

(혹은 이에 파생된 삼항 연산자 (isNull) ? yes : no 와 같은 방식)를 사용하게 된다.

하지만 이러한 로직을 사용하는 코드는 가독성을 떨어트리고

null값이 발생한다는 상황을 항상 고려해주어야 하는 단점이 있다.

 

Optional은 이러한 null값이 발생하는 모든 상황에 대해서 유연하게 대처할 수 있는 방식을 제시한다.

Optional은 null값이 발생할 수 있는 값에 대해서

분기처리 없이, NPE 없이 context를 유지해서 값을 반환할 수 있는 Monad 패턴을 사용한다.

 

이 때의 특이 사항은 Optional은 해당하는 값과

그리고 해당하는 값의 상태(Null인가 아닌가)를 담아서 사용한다고 볼 수 있다.

Optional의 사용 방식과 해당 메서들을 알아보자.

 

1. Optional의 선언, 생성

기본적으로 Optional은 정적 팩토리 메서드를 사용한 객체의 생성 방식을 사용한다.

그리고 이 때, 해당하는 값이 Null인지, 혹은 Null이 될지 모르는 모든 상황에 대한 생성 방식을 제시해

주는데 이때 사용되는 것이 바로 of, empty, ofNullable 이 세 가지 메서드이다.

 

(1) of  :  객체의 값이 무조건 Null이 아니라고 판단될 때 사용하는 메서드이다.

public static <T> Optional<T> of(T value) {
    return new Optional<>(Objects.requireNonNull(value)); }

 

그런데 왜 명확히 Null이 아닌 값을 받는 경우 Null이 아닌데도 Optional을 사용하는가? 라는 생각이 들 수 있다.

우리가 원하는 것은
1. 해당하는 값을 받고,

2. 비즈니스 로직을 실행할 때, 이후 생성될 null값이 나올 수 있는 경우 또한 고려해야 한다. 예를 들어서

 

어떤 고객의 id를 validation처리를 통해서 무조건 있는 값으로 받아 와서

해당하는 id의 고객의 정보를 무조건적으로 얻을 수 있다고 가정을 해서 of로 받아왔다고 하자.

그리고 이 고객의 정보에서 원하는 것을 받으려고 할 때, 다음과 같이 코드를 짤 수 있다.

public String getCityOfMemberFromMember(Member member) {
	return Optional.of(member)
    	.map(Member::getDetail)
        .map(Detail::getAddress)
        .map(Address::getCity)
        .orElse("NoWhere")       }

 

위 코드는 Optional을 통해서 정보를 얻는 코드인데, 이때, 만약 해당하는 주소를 적지 않은 고객이라면 

3번째 map(Detail::getAddress)에서 null을 반환하기에 그 다음 줄 부터 NPE가 발생할 것이다.

이러한 모든 경우까지 고려해서 안전하게 null처리를 할 수 있는게 Optional의 장점이고,

그래서 of메서드 또한 사용할 만 하다고 생각 할 수 있다.

 

(2) empty :  객체의 값이 무조건 Null일 때 사용하는 메서드이다.

public static<T> Optional<T> empty() {
    Optional<T> t = (Optional<T>) EMPTY;
    return t;			}

이 또한 왜 사용하는 지 모를 수 있으나, 간략하게 설명하자면

앞서 예시에서 연산 중 반환되는 값이 null일 경우가 존재한다고 했는데,

optional 사용 도중 이러한 경우를 처리할 때 단순히 null 값을 반환하는게 아닌

Optional.empty()를 반환해서 값이 없음을 표현하고, 마지막 최종 반환 연산에서 이를 처리하기 위해 사용되는데

중점을 두었다고 보면 된다.

 

(3) ofNullable  :  객체의 값의 Null 유무 상관 없이 사용하는 핵심 생성자.

아마 사용하게 된다면 이 생성자를 통한 Optional의 생성이 주를 이룰 것 같다.

대부분의 코드와 로직에서 null값이 반환될 수 있는 가능성만을 열어둘 뿐, 위의 두 개의 생성자들을

사용할 상황 처럼 확정적인 상황은 없다. 따라서 이 메서드를 통한 생성을 많이 할 것이다.

public static <T> Optional<T> ofNullable(T value) {
    return value == null ? (Optional<T>) EMPTY
                         : new Optional<>(value);	}
// id를 통해 Member의 정보를 받을 때, 타입, 변수 선언 및 정의하는 방식.
Optional<Member> maybeMember = Optional.ofNullable(Member.getMemberById(id))

 

 

다음 글에는 이를 통해서 중간처리 및 최종 처리를 위한 메서드들과 사용 방식을 소개 하겠다.