optional jihoon - GANGNAM-JAVA/JAVA-STUDY GitHub Wiki

Optional

API Note: Optional is primarily intended for use as a method return type where there is a clear need to represent "no result," and where using null is likely to cause errors. A variable whose type is Optional should never itself be null; it should always point to an Optional instance.

'๊ฒฐ๊ณผ ์—†์Œ(no result)'์„ ๋ช…ํ™•ํžˆ ๋‚˜ํƒ€๋‚ผ ํ•„์š”๊ฐ€ ์žˆ๊ณ , null์„ ๋ฆฌํ„ดํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์€ ์ƒํ™ฉ์—์„œ ๋ฉ”์„œ๋“œ์˜ ๋ฆฌํ„ด ํƒ€์ž…์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด Optional์˜ ์ฒ˜์Œ ์˜๋„๋‹ค. Optional ํƒ€์ž…์˜ ๋ณ€์ˆ˜๋Š” ๊ฐ’์ด ์ ˆ๋Œ€ null ์ด์–ด์„œ๋Š” ์•ˆ ๋˜๋ฉฐ, ํ•ญ์ƒ Optional ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€๋ฆฌ์ผœ์•ผ ํ•œ๋‹ค.

  • Optional ํด๋ž˜์Šค๋Š” 'T'ํƒ€์ž…์˜ ๊ฐ์ฒด๋ฅผ ํฌ์žฅํ•ด ์ฃผ๋Š” Wrapper class ์ด๋‹ค.
  • ๋”ฐ๋ผ์„œ, Optional ์ธ์Šคํ„ด์Šค๋Š” ๋ชจ๋“  ํƒ€์ž…์˜ ์ฐธ์กฐ ๋ณ€์ˆ˜๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Optional ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ œ๊ณต๋˜๋Š” ๋ฉ”์†Œ๋“œ๋กœ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ NullPointerException ์˜ˆ์™ธ๋ฅผ ํšŒํ”ผํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, ๋ณต์žกํ•œ ์กฐ๊ฑด๋ฌธ ์—†์ด๋„ null ๊ฐ’์œผ๋กœ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

์ƒ์„ฑ

  • of

    • ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜
      static <T> Optional<T> of(T value)
    • ๊ฐ’์ด null์ผ ๊ฒฝ์šฐ NullPointerException ๋ฐœ์ƒ
    • ์ฆ‰, ์›์ž๊ฐ’์ด ๋ฐ˜๋“œ์‹œ ์žˆ์–ด์•ผ ํ•˜๊ณ , ์—†์œผ๋ฉด ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  ์‹ถ์„ ๋–„ ์‚ฌ์šฉ
    • ์˜ˆ์‹œ
      Optional<String> opt = Optional.of("test");
  • ofNullable

    • ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜
      static <T> Optional<T> ofNullable(T value)
    • ๊ฐ’์ด null์ผ ์ˆ˜๋„ ์žˆ์„ ๋•Œ ์‚ฌ์šฉ
    • ๊ฐ’์ด null์ผ ๊ฒฝ์šฐ ๋น„์–ด์žˆ๋Š” Optional ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฆฌํ„ดํ•˜๊ณ , ์ค‘๊ฐ„ ๋ฐ ์ข…๋‹จ ์ฒ˜๋ฆฌ ๋ฉ”์†Œ๋“œ ์ฒด์ด๋‹์„ ํ†ตํ•ด ์›ํ•˜๋Š” ๊ฐ’ ๋„์ถœ ๊ฐ€๋Šฅ
    • ์ฒด์ด๋‹์„ ํ•˜๋”๋ผ๋„ ๊ฐ’์ด null์ผ ๊ฒฝ์šฐ ์ค‘๊ฐ„ ์—ฐ์‚ฐ์€ ์ˆ˜ํ–‰๋˜์ง€ ์•Š์œผ๋ฉฐ ์ข…๋‹จ ์—ฐ์‚ฐ๋งŒ ์ˆ˜ํ–‰๋œ๋‹ค.
    • ์˜ˆ์‹œ
      Optional<String> opt = Optional.ofNullable("test");
  • empty

    • ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜
      static <T> Optional<T> empty()
    • ๋น„์–ด์žˆ๋Š” Optional ์ธ์Šคํ„ด์Šค๋ฅผ ์ž„์˜๋กœ ์ƒ์„ฑํ•œ๋‹ค.
    • ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋ถ„๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ฑฐ๋‚˜, ๋ฆฌํ„ด ๊ฐ’์ด ์—†์„ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•œ๋‹ค.
    • ์˜ˆ์‹œ
      Optional<String> opt = Optional.empty();

์ค‘๊ฐ„ ์ฒ˜๋ฆฌ

์ƒ์„ฑ๋œ Optional ์ธ์Šคํ„ด์Šค์— ๋ฉ”์†Œ๋“œ๋ฅผ ์—ฐ๊ฒฐํ•˜์—ฌ ์›ํ•˜๋Š” ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.
๊ฐ ๋ฉ”์†Œ๋“œ๋“ค์€ ๋‹ค์‹œ Optional ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฆฌํ„ดํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฒด์ด๋‹ ์—ฐ์‚ฐ์„ ํ†ตํ•ด ๋ฐ˜๋ณต ์—ฐ๊ฒฐ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

  • filter

    • ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜
    Optional<T> filter(Predicate<? super T> predicate)
    • filter๋Š” ๊ฐ’์„ ๋ฐ›์•„์„œ boolean ๊ฐ’์„ ๋ฆฌํ„ดํ•˜๋Š” Predicate ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค.
    • ๊ทธ ๊ฒฐ๊ณผ๊ฐ€ true๋ฉด ๊ฐ’์ด ์กด์žฌํ•˜๋Š” Optional ์ธ์Šคํ„ด์Šค๋ฅผ, false๋ฉด ๋น™ Optional ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.
    • ์˜ˆ์‹œ
      Optional.ofNullable("111").filter(v -> "111".equals(v));
  • map

    • ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜
    <U> Optional<U> map(Function<? super T,? extends U> mapper)
    • ์ธ์ž์™€ ๋ฆฌํ„ด๊ฐ’์„ ๋ชจ๋‘ ์ง€์ •ํ•˜๋Š” Function ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค.
    • ์•„๋ž˜ ์˜ˆ์‹œ์˜ Integer์˜ parseInt ํ•จ์ˆ˜๋Š” ์ด๋ฏธ ์ธ์ž์™€ ๋ฆฌํ„ด๊ฐ’์ด ๊ณ ์ •๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ํƒ€์ž… ์ถ”๋ก ์„ ํ†ตํ•ด Function ์ธํ„ฐํŽ˜์ด์Šค์˜ ์ธ์ž์™€ ๋ฆฌํ„ด ํƒ€์ž…์ด ์ž๋™ ์„ค์ •๋œ๋‹ค.
    • map์€ Optional๋กœ ๊ฐ์‹ธ์ง„ ๊ฐ’์„ ๋‚ด๋ถ€์— ๊ตฌํ˜„ํ•œ Function ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด ๋ณ€ํ™˜ํ•ด์„œ ๋ฆฌํ„ดํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.
    • ์˜ˆ์‹œ
      Optional.ofNullable("001").map(Integer::parseInt);
  • flatMap

    • ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜
    <U> Optional<U> flatMap(Function<? super T,? extends Optional<? extends U>> mapper)
    • map๊ณผ ๋น„์Šทํ•˜์ง€๋งŒ, Function ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ฆฌํ„ด์„ Optional๋กœ ํ•ด์•ผ ํ•œ๋‹ค.
    • ์˜ˆ์‹œ
      Optional.ofNullable("001").flatMap(v -> Optional.of(Integer.parseInt(v)));
  • or

    • ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜
    Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)
    • ๊ฐ’์ด ์กด์žฌํ•˜๋ฉด ํ•ด๋‹น ๊ฐ’์„ ๊ฐ์‹ธ๋Š” Optional ์ธ์Šคํ„ด์Šค๋ฅผ, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด suppier ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ƒ์„ฑ๋œ Optional ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.
    • ๋ฆฌํ„ด ํƒ€์ž…์ด Optonal์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ณ„์†ํ•ด์„œ orElse์™€ ๊ฐ™์€ Optional ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๋“ค์„ ์—ฐ์‡„์ ์œผ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.
    • ๊ธฐ์กด์˜ orElseGet๋‚˜ orElse๊ฐ€ ์ฃผ๋กœ ๋ฉ”์„œ๋“œ ์ฑ„์ธ(Chain)์˜ ์ตœ๋ง๋‹จ์—์„œ ์ตœ์ข…์ ์œผ๋กœ Optional ๊ฐ์ฒด๊ฐ€ ๋‹ด๊ณ  ์žˆ๋Š” ๊ฐ’์„ ์–ป๊ธฐ์œ„ํ•ด์„œ ์‚ฌ์šฉ๋๋‹ค๊ณ  ํ•œ๋‹ค๋ฉด, or์€ ์ฃผ๋กœ ๋ฉ”์„œ๋“œ ์ฑ„์ธ์˜ ์ค‘๊ฐ„์—์„œ Optionl ๊ฐ์ฒด๊ฐ€ ๋น„์–ด์žˆ์„ ๊ฒฝ์šฐ ๊ฐ’์„ ์ฑ„์›Œ์ฃผ๊ธฐ ์œ„ํ•œ ์šฉ๋„๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์˜ˆ์‹œ
      String coffeeToMake = Optional
          .ofNullable(order)
          .map(Order::getCoffee)
          .orElse("Americano");
      System.out.println("๋งŒ๋“ค ์ปคํ”ผ : " + coffeeToMake);

์ข…๋‹จ ์ฒ˜๋ฆฌ

Optional์„ ๋๋‚ธ๋‹ค๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์—, ๋ญ”๊ฐ€ ๋ฆฌํ„ดํ•˜๋Š” ์ž‘์—…์ด ์žˆ๋‹ค๋ฉด Optional ์ธ์Šคํ„ด์Šค๊ฐ€ ์•„๋‹Œ, ๊ฐ’ ์ž์ฒด๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.

  • ifPresent

    • ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜
    void ifPresent(Consumer<? super T> action)
    • Optional ๊ฐ’์ด ์žˆ์„ ๊ฒฝ์šฐ ์ˆ˜ํ–‰ํ•  ๋กœ์ง์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์ •์˜๋˜๋Š” ์ž‘์—…์€ Consumer ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋กœ, ๋ฆฌํ„ด ๊ฐ’ ์ด ์—†๋Š” ์ˆœ์ˆ˜ ์†Œ๋น„ ๋กœ์ง์ด์–ด์•ผ ํ•œ๋‹ค.
    • ๋ฆฌํ„ด ๊ฐ’์ด ์žˆ๋Š” ์ž‘์—…์„ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด map์„ ํ™œ์šฉํ•˜๋ฉด ๋œ๋‹ค.
    • ์˜ˆ์‹œ
      Optional.ofNullable("111").ifPresent(v -> {
          // todo
      })
  • ifPresentOrElse

    • ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜
    void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
    • ifPresent์™€ ๋‹ฌ๋ฆฌ, ๊ฐ’์ด ์กด์žฌํ•˜์ง€ ์•Š์„ ๋•Œ์—๋„ ์ˆ˜ํ–‰ํ•  ๋กœ์ง์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์˜ˆ์‹œ
      Optional.ofNullable(order)
      .map(Order::getCoffee)
      .ifPresentOrElse(
          coffee -> System.out.println("๋งŒ๋“ค ์ปคํ”ผ: " + coffee),
          () -> System.out.println("๋งŒ๋“ค ์ปคํ”ผ: " + user.getFavoriteCoffee())
      );
  • isPresent

    • ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜
    bolean isPresent()
    • Optional ์ธ์Šคํ„ด์Šค๊ฐ€ ๋น„์–ด์žˆ๋‹ค๋ฉด false๋ฅผ, ๊ทธ ๋ฐ˜๋Œ€๋ผ๋ฉด true๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.
    • ์˜ˆ์‹œ
      if(Optional.ofNullable("111").isPresent()){
      	// todo
      }
  • get

    • ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜
    • ์‹ค์ œ ๊ฐ’์„ ๋ฆฌํ„ดํ•œ๋‹ค. ๊ทธ ๊ฐ’์ด null์ด๋ฉด null์„ ๊ทธ๋Œ€๋กœ ๋ฆฌํ„ดํ•˜๊ธฐ ๋•Œ๋ฌธ์— exception์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์˜ˆ์‹œ
      City city = Optional.ofNullable(city).get()
  • orElse

    • ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜
    T orElse(T other)
    • ๊ฐ’์ด ์กด์žฌํ•˜๋ฉด ์‹ค์ œ ๊ฐ’์„, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด other๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค. default ๊ฐ’์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์˜ˆ์‹œ
      return Optional.ofNullable(null).orElse("zzz");
  • orElseGet

    • ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜
    T orElseGet(Supplier<? extends T> supplier)
    • orElse์™€ ๋น„์Šทํ•˜์ง€๋งŒ, ์ธ์ž๊ฐ€ ๊ฐ์ฒด๊ฐ€ ์•„๋‹Œ Supplier ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค. ์ฆ‰, ๊ฐ’์„ ๊ตฌํ•˜๊ธฐ ์œ„ํ•œ ๋ณ„๋„ ๋กœ์ง์„ ์ถ”๊ฐ€๋กœ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์˜ˆ์‹œ
      return Optional.ofNullable(null).orElseGet(() -> {
          String returnStr = "default";
          // todo
          return returnStr;
      });
  • orElseThrow

    • ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜
    <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X extends Throwable // Java8
    T orElseThrow() // Java10
    • Optional ๊ฐ์ฒด๊ฐ€ ๋น„์–ด์žˆ๋‹ค๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์ •์˜ํ•œ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.
    • ์ธ์ž๊ฐ€ ์—†๋Š” ๋ฉ”์„œ๋“œ์˜ ๊ฒฝ์šฐ
    • ์˜ˆ์‹œ
      return Optional.ofNullable(null).orElseThrow(() -> {
          return new NullPoitnerException();
      });
      
      return Optional.ofNullable(null).orElseThrow();
  • stream

    • ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜
    Stream<T> stream()
    • ์˜ต์…”๋„ ๊ฐ์ฒด๋ฅผ ์ŠคํŠธ๋ฆผ ๊ฐ์ฒด๋กœ ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์˜ˆ์‹œ
      Stream<Optional<String>> optionalStream =
          Stream.of(Optional.of("Americano"), Optional.of("Latte"), Optional.empty(), Optional.of("Cappuccino"));
      List<String> validCoffeeList = optionalStream
          .flatMap(Optional::stream)
          .collect(Collectors.toList());
      System.out.println("๋งŒ๋“ค ์ปคํ”ผ ๋ชฉ๋ก: " + validCoffeeList);

etc

  • ofNullable์ด ์žˆ๋Š”๋ฐ, of๊ฐ€ ์กด์žฌํ•˜๋Š” ์ด์œ 
    • of๋ฅผ ์“ด๋‹ค๋Š” ๊ฒƒ์€ ๊ฐ’์ด null์ด ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ํ™•์‹ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋Ÿฌํ•œ ์ƒํ™ฉ์—์„œ ofNullable๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ null์ž„์—๋„ ์—๋Ÿฌ ์—†์ด ์กฐ์šฉํžˆ ์ž˜๋ชป๋œ ์ƒํƒœ๋กœ ๋Œ์•„๊ฐ€๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.
  • map๊ณผ flatmap ์ฐจ์ด
public class Person {

    private Optional<Car> optionalCar;

    public Optional<Car> getOptionalCar() {
        return optionalCar;
    }
}

public class Car {

    private Optional<Insurance> optionalInsurance;

    public Optional<Insurance> getOptionalInsurance() {
        return optionalInsurance;
    }
}

public class Insurance {

    private String name;

    public String getName() {
        return name;
    }

}

public class Test {

    // map cannot deal with nested Optionals
    public Optional<String> getCarInsuranceName(Person person) {
        return person.getOptionalCar()
                .map(Car::getOptionalInsurance) // โ‘  leads to a Optional<Optional<Insurance>
                .map(Insurance::getName);       // โ‘ก
    }

}
public Optional<String> getCarInsuranceName(Person person) {
    return person.getOptionalCar()
                 .flatMap(Car::getOptionalInsurance)
                 .map(Insurance::getName);
}

์ฐธ๊ณ 

โš ๏ธ **GitHub.com Fallback** โš ๏ธ