본문 바로가기
스프링 스터디 (인프런)/더 자바 8

섹션 4. Optional-Optional 소개

by 백엔드 개발자 2023. 4. 20.

5 Optional

1.  Optional 소개

 

 

getProgress의 StudyDuration(공부 시간)을 출력하려고 시도하다가 NullpointException이 발생한 상황이다.

 

 

public Progress progress;

public OnlineClass(Integer id, String title, boolean closed) {
    this.id = id;
    this.title = title;
    this.closed = closed;
}

그 이유는 OnlineClass의 progress값이 Null이기 때문이다.

그래서 Null의 메서드를 호출하려고 했기 때문에 Null을 참조하는 과정에서 에러가 발생했다.

 

 

OnlineClass spring_boot = new OnlineClass(1, "spring boot", true);
Progress progress = spring_boot.getProgress();
if ( progress != null) {
    System.out.println(progress.getStudyDuration());
}

이런 코드의 문제점은 에러를 발생시키기 좋다는 것이다.

 

자바 프로그래밍에서 NullPointerException을 종종 보게 되는 이유

     null을 리턴하니까! && null 체크를 깜빡했으니까!

 

 

 

 

 

메소드에서 작업 중 특별한 상황에서 값을 제대로 리턴할 수 없는 경우 선택할 수 있는 방법(자바 8 이전의 상황)

 

1. 예외를 던진다. (비싸다, 스택트레이스를 찍어두니까.)

public Progress getProgress() {
    if (this.progress ==null){
      throw new IllegalStateException();
    }
    return progress;
}

 

2. null을 리턴한다. (비용 문제가 없지만 그 코드를 사용하는 클리어인트 코드가 주의해야 한다.)

 

 

 

 

 

 

 

 

 

public Optional<Progress> getProgress() {
    return Optional.ofNullable(progress);
}

     (자바 8부터) Optional을 리턴한다. (클라이언트에 코드에게 명시적으로 빈 값일 수도 있다는 걸 알려주고, 빈 값인 경우에 대한 처리를 강제한다.)

 

Null일수도 있는 값이면 ofNullable 사용.

Optional.of(..)는 파라미터값이 반드시 null이 아닐경우에만 사용 가능.

 

 

 

 

 

 

Optional

     오직 값 한 개가 들어있을 수도 없을 수도 있는 컨네이너.

 

주의할 것

     리턴값으로만 쓰기를 권장한다. (메소드 매개변수 타입, 맵의 키 타입, 인스턴스 필드 타입으로 쓰지 말자.)

 

 

1. 메서드 매개변수 Optional 예제

위험한 코드.

spring_boot.setProgress(null);
public void setProgress(Optional<Progress> progress) {
    if(progress != null) {
        progress.ifPresent(p -> this.progress = p);
    }
}

호출하는쪽에서 얼마든지 null을 넣을 수 있다.

그러면 null의 ifPresent함수를 실행하므로 NullpointException이 발생하고, 한번더 null체크를 해야 한다.

 

 

2. Map Optional

Map의 특징 중 하나는 key값이 null일 수 없다는 것이다.

그런데 Optional을 사용하면 key값이 비어있을 수도, 아닐 수도 있다는 의미가 되므로 좋지 않다.

 

     Optional을 리턴하는 메소드에서 null을 리턴하지 말자.

Null을 리턴하도록 코드를 구성하면 ifPresent를 사용하다가 NullpointException이 발생하게 된다.

return Optional.empty();

정말 리턴할 값이 없다면 empty를 사용하자.

 

 

 

     프리미티브 타입용 Optional을 따로 있다. OptionalInt, OptionalLong,...

Optional.of(10);

이런식으로 넣을 수는 있으나, 이렇게 되면 박싱, 언박싱이 발생하는 문제가 있다. -> 성능저하

OptionalInt.of(10);

이런식으로 추천.

 

 

     Collection, Map, Stream Array, Optional Opiontal로 감싸지 말 것.

 (컨테이너 성격의 인스턴스를 감싸지 말라는 뜻)

 

 

참고

     https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html

     https://www.oracle.com/technical-resources/articles/java/java8-optional.html

     이팩티브 자바 3, 아이템 55 적절한 경우 Optional을 리턴하라.