모르지 않다는 것은 아는것과 다르다.

Java

Optional

채마스 2022. 2. 26. 00:12

Optional

  • null일 수도있고, 비어있을 수도 있다.
  • 메소드에서 작업 중 특별한 상황에서 값을 제대로 리턴할 수 없는 경우 선택할 수 있는 방법
    • 예외를 던진다. (비싸다, 스택트레이스를 찍어두니까.)
    • null을 리턴한다. (비용 문제가 없지만 그 코드를 사용하는 클리어인트 코드가 주의해야 한다.)
    • (자바 8부터) Optional을 리턴한다. (클라이언트에 코드에게 명시적으로 빈 값일 수도 있다는 걸 알려주고, 빈 값인 경우에 대한 처리를 강제한다.)
  • Optional
    • 오직 값 한개가 들어있을 수도 없을 수도 있는 컨네이너.
  • 주의할 것
    • 리턴값으로만 쓰기를 권장한다. (메소드 매개변수 타입, 맵의 키 타입, 인스턴스 필드 타입으로 쓰지 말자.)
    • Optional을 리턴하는 메소드에서 null을 리턴하지 말자. -> null 말고 Optional.empty를 리턴하자.
    • 프리미티브 타입용 Optional을 따로 있다. OptionalInt, OptionalLong,...
    • Collection, Map, Stream Array, Optional은 Opiontal로 감싸지 말 것. -> 이 자체로 이미 비어있는지 안비어있는지 알 수 있는 컨테이너 성격의 인스턴스들이다.





Optional API

 

Optional 만들기

  • Optional.of()
  • Optional.ofNullable()
  • Optional.empty()

코드 예시

String name = "hyunwook";
String nullName = null;

Optional<String> myName = Optional.of(name); // null 아닐 때
Optional<String> myName = Optional.empty();// 빈 상자
Optional<String> myName = Optional.ofNullable(name); 
Optional<String> myName = Optional.ofNullable(nullName); // null 인지 아닌지 모를때





Optional에 값이 있는지 없는지 확인하기

  • isPresent()
  • isEmpty() (Java 11부터 제공)



Optional에 있는 값 꺼내오기

get()

  • 만약에 비어있는 Optional에서 무언가를 꺼낸다면?? -> NoSuchElementException이 발생한다.



ifPresent(Consumer)

  • Optional 이 null 이 아니라면 action 을 실행한다.
  Optional<OnlineClass> result = springClasses.stream()
          .filter(oc -> oc.getTitle().startsWith("jpa"))
          .findFirst();

  result.ifPresent(oc -> System.out.println(oc.getTitle()));






orElse(T)

  • Optional이 null이 아니라면 Optional 안의 값을, null 이라면 T로 공급된 값을 리턴한다.
  Optional<OnlineClass> result = springClasses.stream()
          .filter(oc -> oc.getTitle().startsWith("jpa"))
          .findFirst();

  // 경우 1
  OnlineClass onlineClass = result.orElse("default email");

  // 경우 2
  OnlineClass onlineClass = result.orElse(createNewClass());
  private static OnlineClass createNewClass(){
      return new OnlineClass(10, "new class", false);
  }
  • 경우 1 일때, result 가 null 이 아니라면 해당 값이 추출되고, null 이면 "default email" 이 반환된다.
  • 경우 2 일때, null 이든 아니든 createNewClass() 메소드가 호출되면서 새로운 인스턴스가 생성된다. -> 조심해야한다. -> 이럴 경우엔 orElseGet 을 사용하는 것이 바람직하다.
  • 정리하면 orElse 일 경우, null 일 경우 반환값이 primitive type 이라면 사용하는것이 바람직하지만, 반환값이 새로운 객체를 생성하는 것이라면 주의 해야서 사용해야 한다.






orElseGet(Supplier)

  • Optional 이 Null 이 아니라면 Optional 안의 값을 리턴하고, null 이라면 supplier로 공급되는 값을 리턴한다.
  Optional<OnlineClass> result = springClasses.stream()
          .filter(oc -> oc.getTitle().startsWith("jpa"))
          .findFirst();

  OnlineClass onlineClass = result.orElseGet(() -> createNewClass());
  private static OnlineClass createNewClass(){
      return new OnlineClass(10, "new class", false);
  }
  • 위의 경우 result 가 null 이 아니라면 해당 값이 추출되고, null 인 경우에만 createNewClass() 메소드가 호출되면서 새로운 인스턴스가 생성된다.






orElseThrow()

  • Optional에 값이 있으면 가져오고 없는 경우 에러를 던져라.
  Optional<OnlineClass> result = springClasses.stream()
          .filter(oc -> oc.getTitle().startsWith("jpa"))
          .findFirst();

  OnlineClass onlineClass = result.orElseThrow(IllegalStateException::new);






Optional에 들어있는 값 걸러내기

  • Optional filter(Predicate)
  Optional<OnlineClass> result = springClasses.stream()
          .filter(oc -> oc.getTitle().startsWith("jpa"))
          .findFirst();

  Optional<OnlineClass> onlineClass = result.filter(oc -> !oc.isClosed());





Optional에 들어있는 값 변환하기

  • Optional map(Function)
    Optional<OnlineClass> result = springClasses.stream()
            .filter(oc -> oc.getTitle().startsWith("jpa"))
            .findFirst();

    Optional<Integer> integer = result.map(OnlineClass::getId);
  • Optional flatMap(Function): Optional 안에 들어있는 인스턴스가 Optional인 경우에 사용하면 편리하다.
    • 반환값이 Optional<Optional<Progress>> 일 경우에 사용하면 편리하다. -> 한겹을 까준다.




REFERENCES

'Java' 카테고리의 다른 글

Stream  (0) 2022.02.26
Static 변수와 Static 메서드  (0) 2022.02.26
Object 클래스  (0) 2022.02.26
Exception  (0) 2022.02.26
Class 클래스  (0) 2022.02.26