Optional은 Java Stream과 함께 도입된 컨셉이며, 어떤 이유로 사용하는지 개념과 예제를 소개합니다.

Stream Optional

Optional은 어떤 객체를 보관하는 컨테이너 클래스이며, null 체크 같은 간단한 기능을 제공합니다.

Optional 객체는 non-null(null이 아닌) 객체이지만, 대신 어떤 값을 갖고 있는데 그 값이 null일 수 있고, 또는 null이 아닐 수 있습니다.

기존엔 객체에 대한 null check 코드를 직접 구현하고 예외처리를 했다면, Optional은 이런 기본적인 기능과 예외처리 기능들을 제공하여 쉽게 다룰 수 있게 합니다.

Optional 객체 생성

non-null 값을 갖고 있는 Optional

아래 예제는 Optional 객체를 생성하고, Optional 안의 데이터를 가져옵니다.

  • Optional.of(string) : string 객체를 갖고 있는 Optional 객체를 생성
  • op.get() : Optional이 갖고 있는 객체 리턴
import java.util.Optional;

public class Example {

    public static void main(String[] args) {

        String string = "Apple";

        Optional<String> op = Optional.of(string);
        System.out.println(op.get());
    }
}

Output:

Apple

null 값을 갖고 있는 Optional

null을 갖고 있는 Optional 객체를 생성하려면 Optional.ofNullable(obj)로 null 객체를 전달하면 됩니다.

Optional.get()으로 객체를 가져오려고 할 때, null이기 때문에 Optional 객체가 NoSuchElementException 에러를 발생시킵니다.

import java.util.NoSuchElementException;
import java.util.Optional;

public class Example {

    public static void main(String[] args) {

        String string = null;

        try {
            Optional<String> nullOp = Optional.ofNullable(string);
            System.out.println(nullOp.get());
        } catch (NoSuchElementException e) {
            System.out.println(e);
        }
    }
}

Output:

java.util.NoSuchElementException: No value present

Optional.isPresent() : non-null 값을 갖고 있는지 확인

Optional.isPresent()는 Optional이 non-null 객체를 갖고 있을 때 true를 리턴합니다. 우리가 if문으로 객체에 대해서 null 체크를 하는 것과 비슷합니다.

아래와 같은 방식으로 Optional로 null check를 할 수 있으며, null이 아닌 경우 특정 코드를 수행시킬 수 있습니다.

import java.util.Optional;

public class Example {

    public static void main(String[] args) {

        Optional<String> nullOp = Optional.ofNullable(null);
        if (nullOp.isPresent()) {
            System.out.println("nullOp.get(): " + nullOp.get());
        }

        Optional<String> op = Optional.of("Apple");
        if (op.isPresent()) {
            System.out.println("op.get(): " + op.get());
        }
    }
}

Output:

op.get(): Apple

Optional.ifPresent() : functional interface

위 코드는 ifPresent()를 사용하여 좀 더 간단히 구현할 수 있습니다. ifPresent()isPresent()와 목적이 동일하지만 함수형 인터페이스를 인자로 받는 함수입니다.

Optional이 non-null을 갖고 있을 때 함수에 객체를 전달하며, null을 갖고 있으면 함수를 호출하지 않습니다.

  • non-null 객체를 갖고 있는 op만 함수가 호출됨
  • 함수에 string이 전달되어 Optional.get()을 호출할 필요가 없음
import java.util.Optional;

public class Example {

    public static void main(String[] args) {

        Optional<String> nullOp = Optional.ofNullable(null);
        nullOp.ifPresent(str -> System.out.println("nullOp.get(): " + str));

        Optional<String> op = Optional.of("Apple");
        op.ifPresent(str -> System.out.println("op.get(): " + str));
    }
}

Output:

op.get(): Apple

Optional.orElse() : null 객체에 대한 기본 값

Optional이 null 객체를 갖고 있을 때, null 대신에 default 값으로 어떤 값을 항상 갖도록 하고 싶을 수 있습니다.

Optional.orElse(a)는 Optional이 null 값을 갖고 있을 때 a를 리턴합니다.

  • 아래 예제를 보면 nullOp는 null 값을 갖고 있어서 "null op"가 리턴됨
  • op는 non-null 값을 갖고 있어서, 그 값이 리턴됨
import java.util.Optional;

public class Example {

    public static void main(String[] args) {

        Optional<String> nullOp = Optional.ofNullable(null);
        System.out.println("nullOp.orElse(): " + nullOp.orElse("null op"));

        Optional<String> op = Optional.of("Apple");
        System.out.println("op.orElse(): " + op.orElse("non-null op"));
    }
}

Output:

nullOp.orElse(): null op
op.orElse(): Apple

Optional.orElseGet() : 함수 결과를 기본값으로

Optional이 null을 갖고 있을 때, 어떤 함수의 결과를 기본 값으로 사용하고 싶을 수도 있습니다.

Optional.orElse()와 용도는 동일하지만, Optional.orElseGet()는 아래 예제처럼 함수를 인자로 전달할 수 있습니다.

import java.util.Optional;

public class Example {

    public static String getDefaultValue() {
        return "ABC";
    }

    public static void main(String[] args) {

        Optional<String> nullOp = Optional.ofNullable(null);
        System.out.println("nullOp.orElseGet(): " + nullOp.orElseGet(() -> getDefaultValue()));

        Optional<String> op = Optional.of("Apple");
        System.out.println("op.orElseGet(): " + op.orElseGet(() -> getDefaultValue()));
    }
}

Output:

nullOp.orElseGet(): ABC
op.orElseGet(): Apple

Optional.orElseThrow() : 기본 값 대신에 Exception 발생

Optional.orElseThrow()는 null 값을 갖고 있을 때, 기본 값을 리턴하는 대신에 Exception 발생시킵니다.

아래 예제를 보시면 쉽게 이해하실 수 있습니다.

import java.util.Optional;

public class Example {

    public static void main(String[] args) {

        try {
            Optional<String> nullOp = Optional.ofNullable(null);
            System.out.println("nullOp.orElseGet(): " + nullOp.orElseThrow(NullPointerException::new));
        } catch (NullPointerException e) {
            System.out.println(e);
        }

        try {
            Optional<String> op = Optional.of("Apple");
            System.out.println("op.orElseGet(): " + op.orElseThrow(NullPointerException::new));
        } catch (NullPointerException e) {
            System.out.println(e);
        }
    }
}

Output:

java.lang.NullPointerException
op.orElseGet(): Apple