Optional <T>이란?

Optional은 null이 올 수 있는 값을 감싸는 Wrapper 클래스입니다. 즉 개발자는 null을 검증하는 로직을 일일이 작성할 필요 없이 Optional로 감싼 후 Optional의 매소드들을 사용해 가공할 수 있습니다.

 

간단하게 Optional 사용하지 않은 코드와 사용한 코드를 살펴보겠습니다. 

 

Box 안에 담겨 있는 Toy를 가져오는 코드입니다. 이때 Toy가 초기화되지 않아서 NullPointerException이 발생합니다. 

class Box{

    Toy toy;

    public Toy getToy(){
        return toy; 
    }

}

class Toy{

    String name;

    public String getName() {
        return name;
    }
}

public class Main {
    public static void main(String[] args) throws IOException {
        Box box = new Box();
        Toy toy = box.getToy();
        System.out.println(toy.getName());
    }
}

1. Optional 사용 x 

public class Main {
    public static void main(String[] args) throws IOException {
        Box box = new Box();
        Toy toy = box.getToy();

        if(toy !=null){
            System.out.println(toy.getName());
        }
    }
}
  • toy에 대한 null 체크를 해줘야 합니다. (null 체크를 했으므로 정상 동작합니다.)

2. Optional 사용

class Box{

    Toy toy;

    public Optional<Toy> getToy(){
        return Optional.ofNullable(toy); // Optional로 감싸서 반환합니다.
    }
}
public class Main {
    public static void main(String[] args) throws IOException {
        Box box = new Box();
        Optional<Toy> toy = box.getToy();
        toy.ifPresent(System.out::println);
    }
}
  • ifPresent()를 통해서 값의 null 체크를 하고 null이 아닐 경우 출력합니다.

안전하게 null 체크를 할 수 있고, 코드가 간결해져 가도성이 올라간 것을 확인할 수 있습니다.


Optional 활용하기

 

1. Optional.of(), Optional.ofNullable()

Optional.of()와 Optional.ofNullable() 어떠한 값을 Optional로 감쌀 때 이용됩니다. 

 

둘의 차이점은 null을 담는 것을 허용하는 차이입니다.

public class Main {
    public static void main(String[] args) throws IOException {

        Optional<String> o = Optional.of(null); // NullPointerException 발생
        Optional<String> s = Optional.ofNullable(null);
    }
}
  • null이 들어올 가능성이 있는 곳은 Optional.ofNullable 사용하면 됩니다. 

2. ifPresent()

Consumer을 인자로 받습니다. 즉 값이 존재한다면, action.accept를 진행하고, 없다면 실행하지 않습니다.

public void ifPresent(Consumer<? super T> action) {
    if (value != null) {
        action.accept(value);
    }
}
public class Main {
    public static void main(String[] args) throws IOException {

        Optional<String> str = Optional.ofNullable(null);
        str.ifPresent(System.out::println);
    }
}

 

  • str이 null 이므로 출력하지 않는 모습을 확인할 수 있습니다.

3. isPresent(), isEmpty()

null의 유무를 판별하고, boolean값을 반환합니다. 

public class Main {
    public static void main(String[] args) throws IOException {

        Optional<String> str = Optional.ofNullable(null);
        boolean present = str.isPresent();
        boolean empty = str.isEmpty();
    }
}

4. orElse()

Optional 안의 값을 비교하는 연산을 수행하게 됩니다. 만약 null일 경우 인자로 받는 것을 반환해줍니다.

public class Main {
    public static void main(String[] args) throws IOException {

        Optional<String> str1 = Optional.ofNullable("hi");
        String string1 = str1.orElse(new String("asdf")); // hi값이 있으므로 hi 반환
        
        Optional<String> str2 = Optional.ofNullable(null);
        String string2 = str1.orElse(new String("asdf")); // null 이므로 asdf 반환
    }
}
  • 값이 null일 경우 원하는 것으로 반환해주는 장점이 있습니다.

5. orElseGet()

Optional 안이 null인지 먼저 확인합니다. 만약 인자로 전달되는 Supplier를 실행합니다.

public class Main {
    public static void main(String[] args) throws IOException {

        Optional<String> str1 = Optional.ofNullable("hi");
        String string1 = str1.orElseGet(() -> "asdf");
        Optional<String> str2 = Optional.ofNullable(null);
        String string2 = str1.orElseGet(() -> "asdf");
    }
}
  • null 값을 먼저 확인하고, null일 경우에만 Supplier를 실행하여 반환합니다. 

6. orElse() orElseGet() 차이

두 메서드는 인자만 다르고, 같은 결과를 반환해줍니다. 하지만 동작 방식이 다릅니다. 

 

orElse()-> Optional 안의 값이 null이던 말던 return 값을 생성

orElseGet() -> Optional안의 값이 null일 때만 return 값을 생성

orElse()는 return 값을 무조건 생성합니다. 이것은 성능의 차이로 이어질 수 있습니다. 
따라서 특수한 경우를 제외하고는 orElseGet() 이용하는 것이 성능상 좋습니다.

정리

지금까지 Optional이 하는 역할과 Optional을 사용하며 자주 쓰는 메서드들을 알아봤습니다. 잘못된 부분이 있다면 지적해주시면 감사합니다. 

'JAVA' 카테고리의 다른 글

JAVA Enum  (0) 2022.02.24
JAVA Stream  (0) 2022.02.23
JAVA 람다(lambda)  (0) 2022.02.21
JAVA Comparable And Comparator  (0) 2022.02.21
Java 제네릭(Generic)  (0) 2022.02.20