티스토리 뷰

Java

Java8 Optional API

J-Mandu 2022. 5. 6. 09:00

 

Optional이란?

Optional<T> Class는 Integer나 Double Class처럼 'T'타입의 객체를 포장해 주는 Wrapper Class이자 컨테이너 객체입니다.

컨테이너 안에 값이 들어 있을 수도 있고, 값이 없어 비어있는 컨테이너 일수도 있습니다.

해당 Optional은 Java 11 기준으로 설명하겠습니다.


Optional 특징

  • 값이 비어있을 수도 있다는 가정하에 사용하므로 직관성이 좋습니다.
  • Null 값을 직접 사용하지 않아 NullPointerException 예외에 대하여 유연해집니다.
  • Null 체크 기능을 직접 구현 안 해도 됩니다.

Optional 생성

 

1. static <T> Optional<T> of(T value)

명시된 값을 가지는 Optional 객체를 반환합니다.

명시된 값이 아닌 null이 저장되는 경우에는 NullpointerException 예외가 발생합니다.

Optional<String> optional = Optional.of("String");
// null 값이 들어가면 NullPointerException 예외가 발생합니다.
Optional<Object> optional2 = Optional.of(null);

 

2. static <T> Optional<T> ofNullable(T value)

명시된 값이 null이 아니면 명시된 값을 가지는 Optional 객체를 반환하며,

명시된 값이 null일 경우 비어있는 Optional 객체를 반환합니다.

Optional<String> optional2 = Optional.ofNullable("4000");
Assertions.assertThat(optional2).isPresent();

Optional<String> optional = Optional.ofNullable(null);
Assertions.assertThat(optional).isEmpty();

 

3. static <T> Optional<T> empty()

아무런 값도 가지지 않는 비어있는 Optional 객체를 반환합니다.

Optional<Object> optional = Optional.empty();
Assertions.assertThat(optional).isEmpty();

 


Optional 메소드

 

1. boolean isPresent()

저장된 값이 존재하면 true를 반환하고, 값이 존재하지 않으면 false를 반환합니다.

Optional<String> optional = Optional.ofNullable("1234");
Assertions.assertThat(optional.isPresent()).isTrue();

Optional<String> optional2 = Optional.ofNullable(null);
Assertions.assertThat(optional2.isPresent()).isFalse();

 

2. boolean isEmpty()

저장된 값이 존재하지 않으면 true를 반환하고, 값이 존재하면 false를 반환합니다.

Optional<String> optional = Optional.ofNullable(null);
Assertions.assertThat(optional.isEmpty()).isTrue();

Optional<String> optional2 = Optional.ofNullable("1234");
Assertions.assertThat(optional2.isEmpty()).isFalse();

 

3. T get()

Optional 객체에 저장된 값을 반환합니다.

Optional<String> optional = Optional.ofNullable("Foo");
Assertions.assertThat(optional.get()).isEqualTo("Foo");

 

4. void ifPresent(Consumer<? super T> consumer)

값이 존재하면 해당 값으로 Consumer interface에 의한 지정된 작업을 수행합니다.

Optional<String> optional = Optional.ofNullable("Foo");
optional.ifPresent(System.out::println);

 

5. void ifPresentOrElse​(Consumer<? super T> action, Runnable emptyAction)

값이 존재하면 해당 값으로 Consumer interface에 의한 지정된 작업을 하고,

값이 존재하지 않으면 Runnable interface에 의한 지정된 작업을 합니다.

Optional<String> optional = Optional.ofNullable("Foo");
optional.ifPresentOrElse((string) -> Assertions.assertThat(string).isEqualTo("Foo")
                            , () -> Assertions.fail("NullPointerException", new NullPointerException()));

Assertions.assertThatThrownBy(() -> Optional.ofNullable(null)
                                            .ifPresentOrElse((string) -> Assertions.assertThat(string).isEqualTo("Foo")
                                                                , () -> Assertions.fail("NullPointerException"
                                                                                            , new NullPointerException())))
        .isInstanceOf(AssertionError.class);

 

6. Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)

값이 존재하면 해당 값에 대한 Optional 객체가 반환되며,

값이 존재하지 않으면 Supplier interface에 의한 지정된 Optional<T> 객체가 반환됩니다.

String order = "banana";
Optional<String> optional = Optional.ofNullable(order)
                                    .or(() -> Optional.of("apple"));
Assertions.assertThat(optional.get()).isEqualTo("banana");

String order2 = null;
Optional<String> optional2 = Optional.ofNullable(order2)
                                     .or(() -> Optional.of("apple"));
Assertions.assertThat(optional2.get()).isEqualTo("apple");

 

7. T orElse(T other)

저장된 값이 존재하면 해당 값을 반환하고, 값이 존재하지 않으면 매개변수로 전달된 값을 반환합니다.

orElse(T other)에 T other는 Optional에 값이 있든 없든 무조건 실행되기 때문에

새로운 객체를 생성하거나, 새로운 연산을 수행하는 경우에는 orElseGet()을 써야합니다.

String order = "apple";
String eat = Optional.ofNullable(order).orElse("bread");
Assertions.assertThat(eat).isEqualTo("apple");

String order2 = null;
String eat2 = Optional.ofNullable(order2).orElse("bread");
Assertions.assertThat(eat2).isEqualTo("bread");

 

8. T orElseGet​(Supplier<? extends T> supplier)

저장된 값이 존재하면 해당 값을 반환하고, 값이 존재하지 않으면 매개변수로 전달된 Supplier interface에 의한 객체를 반환합니다.

String order = "tomato";
String eat = Optional.ofNullable(order).orElseGet(() -> "banana");
Assertions.assertThat(eat).isEqualTo("tomato");

String order2 = null;
String eat2 = Optional.ofNullable(order2)
                     .orElseGet(() -> {
                                           System.out.println("banana");
                                           return "banana";
                                        });
Assertions.assertThat(eat2).isEqualTo("banana");

 

9. T orElseThrow()

저장된 값이 존재하면 그 값을 반환하고, 값이 존재하지 않으면 NoSuchElementException 예외를 발생시킵니다.

Assertions.assertThat(Optional.ofNullable("짜잔").orElseThrow())
        .isEqualTo("짜잔");

Assertions.assertThatThrownBy(() -> Optional.ofNullable(null).orElseThrow())
        .isInstanceOf(NoSuchElementException.class);

 

10. <X extends Throwable> T orElseThrow​(Supplier<? extends X> exceptionSupplier)

저장된 값이 존재하면 그 값을 반환하고, 값이 존재하지 않으면 매개변수로 전달된 예외를 발생시킵니다.

Assertions.assertThat(Optional.ofNullable("짜잔").orElseThrow())
        .isEqualTo("짜잔");

Assertions.assertThatThrownBy(() -> Optional.ofNullable(null)
                                            .orElseThrow(() -> new NullPointerException()))
        .isInstanceOf(NullPointerException.class);

 

11. Optional<T> filter​(Predicate<? super T> predicate)

저장된 값을 Predicate interface에 의한 구현된 조건이 True일 경우만 Optional<T>로 반환합니다.

class Order {
    private String coffee;

    public String getCoffee() {
        return coffee;
    }

    public void setCoffee(String coffee) {
        this.coffee = coffee;
    }
}

Order order = new Order();
order.setCoffee("딸기라떼");

Optional<Order> optional = Optional.ofNullable(order)
                                .filter((coffee) -> coffee.getCoffee().equals("딸기라떼"));
Assertions.assertThat(optional.isPresent()).isTrue();

Optional<Order> optional2 = Optional.ofNullable(order)
                                .filter((coffee) -> coffee.getCoffee().equals("초코라떼"));
Assertions.assertThat(optional2.isPresent()).isFalse();

 

12. <U> Optional<U> map​(Function<? super T,​? extends U> mapper)

저장된 값을 매개변수로 Function interface에 의한 지정된 값을 Optional에 감싸서 Optional<T>을 반환합니다.

class Order {
    private String coffee;

    public String getCoffee() {
        return coffee;
    }

    public void setCoffee(String coffee) {
        this.coffee = coffee;
    }
}

Order order = new Order();

Optional<String> optional = Optional.ofNullable(order).map(Order::getCoffee);
Assertions.assertThat(optional.isPresent()).isFalse();

order.setCoffee("딸기라떼");

Optional<String> optional2 = Optional.ofNullable(order).map(Order::getCoffee);
Assertions.assertThat(optional2.isPresent()).isTrue();

 

13. <U> Optional<U> flatMap​(Function<? super T,​? extends Optional<? extends U>> mapper)

저장된 값을 매개변수로 Function interface에 의한 지정된 Optional<T>을 반환합니다.

class Order {
    private String coffee;

    public Optional<String> getCoffee() {
        return Optional.ofNullable(coffee);
    }

    public void setCoffee(String coffee) {
        this.coffee = coffee;
    }
}

Order order = new Order();

Optional<String> optional = Optional.ofNullable(order).flatMap(Order::getCoffee);
Assertions.assertThat(optional.isPresent()).isFalse();

order.setCoffee("초코라떼");

Optional<String> optional2 = Optional.ofNullable(order).flatMap(Order::getCoffee);
Assertions.assertThat(optional2.isPresent()).isTrue();

 


주의사

  • return 타입으로만 쓰기를 권장합니다.
    - 메소드 매개변수 타입, 맵의 키 타입, 인스턴스 필드 타입으로 사용하지 않습니다.
  • Optional을 return 하는 메소드에서는 null을 리턴하지 않습니다.
  • 기본형 타입의 Optional은 따로 있습니다.
    - OptionalInt, OptionalLong 등..
  • Collection, Map, Stream Array, Optional은 Optional로 감싸지 않습니다.

 

 

 

 

이로써 공부한 내용을 간략히 정리해보았습니다. 

감사합니다.


출처

https://www.inflearn.com/course/the-java-java8/dashboard

http://www.tcpschool.com/​

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Optional.html