[강의] 인프런 : 더 자바, Java8 섹션 4

haeny-dev·2021년 7월 15일
0
post-thumbnail

📌 섹션 4 : Optional

➕ Optional 소개

A wise man once said you are not a real Java programmer until you've dealt with a null pointer exception. Joking aside, the null reference is the source of many problems because it is often used to denote the absence of a value.

Java SE 8 introduces a new class called java.util.Optional that can alleviate some of these problems.

한 현명한 사람은 널 포인터 예외를 처리하기 전까지는 진정한 Java 프로그래머가 아니라고 말한 적이 있습니다. 농담은 제쳐두고, null 참조는 종종 값의 부재를 나타내는 데 사용되기 때문에 많은 문제의 원인입니다.

Java SE 8에는 이러한 문제 중 일부를 완화할 수 있는 java.util.Optional이라는 새 클래스가 도입되었습니다.

1. 메소드에서 값을 제대로 리턴할 수 없는 경우

  • 예외 를 던진다
    • stacktrace를 찍어두기 때문에 비싼 비용을 발생 시킵니다.
  • null 을 리턴한다
    • 해당 코드를 사용하는 클라이언트 코드가 주의해야 합니다.
  • Java8 부터 Optional 을 리턴한다
    • 클라이언트 코드에게 명시적으로 빈 값일 수도 있다는 것을 알려주고, 빈 값인 경우에 대한 처리를 강제합니다.

2. Optional

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

  • 리턴값으로만 쓰기를 권장합니다.
    • 메소드 매개변수 타입, 맵의 키의 타입, 인스턴스 필드 타입으로 사용하지 말 것을 권장
  • Optional 을 리턴하는 메소드에서 null을 리턴하지 말 것
  • Primitive Type용 Optional이 따로 있음.
  • Collection, Map, Stream Array, Optional은 Optional로 감싸지 말 것

➕ Optional API

예제

public class OnlineClass {

    private Integer id;
    private String title;
    private Progress progress;
    private boolean closed;

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

    public Integer getId() {
        return id;
    }
	...
}
public class Progress {

    private Duration studyDuration;
    private boolean finished;
    
    public Duration getStudyDuration() {
        return studyDuration;
    }
    public void setStudyDuration(Duration studyDuration) {
        this.studyDuration = studyDuration;
    }
}
public static void main(String[] args) {
     /* Java8 이전의 Null을 반환하는 것에 대한 처리
     OnlineClass spring_boot = new OnlineClass(1, "spring boot", true);
     Progress progress = spring_boot.getProgress();
     if(progress != null){
      	System.out.println(progress.getStudyDuration());
     }*/

     /* Optional에서 Primitive 타입의 경우
      * 내부적으로 Boxing, Unboxing이 발생하기 때문에 권장하지 않는다.
      * Primitive 타입용 Optinal을 사용하는게 좋다. */
     OptionalInt.of(134);

     List<OnlineClass> springClasses = new ArrayList<>();
     springClasses.add(new OnlineClass(1, "spring boot", true));
     springClasses.add(new OnlineClass(2, "spring data jpa", true));
     springClasses.add(new OnlineClass(3, "spring mvc", false));
     springClasses.add(new OnlineClass(4, "spring core", false));
     springClasses.add(new OnlineClass(5, "rest api development", false));

     Optional<OnlineClass> optionalOnlineClass = springClasses.stream()
            .filter(x -> x.getTitle().startsWith("spring"))
            .findFirst();

     OnlineClass getOnlineClass = optionalOnlineClass.get();
     System.out.println(getOnlineClass.getTitle());

     /*
      * Optional한 객체를 가져올 때, 바로 get()을 할 경우 RuntimeException 발생 시킬 수 있다.
      * 그러므로, 바로 get() 하지 않고, Null여부에 따른 판단을 해줄 수 있는 메소드를 사용해서 처리하는 것이 좋다.
      * */

     // 해당 객체가 있으면 어떤 처리를 해줘야 할 때
     optionalOnlineClass.ifPresent(x -> System.out.println(x.getTitle()));

     // 있으면 객체를 가져오고 없는 경우 해당 객체 타입을 리턴시키는 경우
     // orElse 같은 경우 해당 객체가 있던 없던 매개변수를 먼저 실행 시키기 때문에 매개변수에 상수와 같이 이미 선언되어 있는 것을 사용하는 것이 좋다.
     OnlineClass onlineClassOrElse = optionalOnlineClass.orElse(createNewClass());

     OnlineClass onlineClassOrElseGet = optionalOnlineClass.orElseGet(App::createNewClass);

     OnlineClass throwExceptionClass = optionalOnlineClass.orElseThrow(IllegalStateException::new);

     Optional<OnlineClass> filteringClass = optionalOnlineClass.filter(OnlineClass::isClosed);

     /* flat map */
     Optional<Optional<Progress>> optionalOptionalProgress = 
     			optionalOnlineClass.map(OnlineClass::getProgress);

     Optional<Progress> optionalProgress = optionalOnlineClass.flatMap(OnlineClass::getProgress);
}

private static OnlineClass createNewClass() {
     System.out.println("creating new online class");
     return new OnlineClass(10, "New class", false);
}

REFERENCE

Optional
Tired of Null Pointer Exceptions? Consider Using Java SE 8's "Optional"!
➕ 이팩티브 자바 3판, 아이템 55 적절한 경우 Optional을 리턴하라.

0개의 댓글