개발/자바

Java 8 Optional 개요

피터JK 2025. 2. 1. 14:34
728x90

Java 8에서 도입된 Optional<T>은 null 처리를 안전하게 할 수 있도록 설계된 컨테이너 클래스입니다. null 값 처리 문제를 보다 안전하고 간결한 방식으로 해결할 수 있습니다.


1. Optional 객체 생성 방법

1.1. Optional.of(T value)

null이 아닌 값을 포함하는 Optional 객체를 생성합니다.

Optional<String> opt = Optional.of("Hello");
System.out.println(opt.get()); // Hello

1.2. Optional.ofNullable(T value)

값이 null일 수도 있을 경우 사용합니다.

Optional<String> opt = Optional.ofNullable(null); // 빈 Optional 반환
System.out.println(opt.isPresent()); // false

1.3. Optional.empty()

빈 Optional 객체를 생성합니다.

Optional<String> opt = Optional.empty();
System.out.println(opt.isPresent()); // false

2. Optional 값 처리 방법

2.1. isPresent() - 값이 존재하는지 확인

Optional<String> opt = Optional.of("Hello");
if (opt.isPresent()) {
    System.out.println(opt.get()); // Hello
}

2.2. ifPresent(Consumer<? super T> consumer) - 값이 있을 때 실행

Optional<String> opt = Optional.of("Hello");
opt.ifPresent(value -> System.out.println("Value: " + value)); // Value: Hello

2.3. orElse(T other) - 기본값 설정

Optional<String> opt = Optional.empty();
System.out.println(opt.orElse("Default Value")); // Default Value

2.4. orElseGet(Supplier<? extends T> supplier) - 기본값을 제공하는 함수 사용

Optional<String> opt = Optional.empty();
System.out.println(opt.orElseGet(() -> "Computed Default Value")); // Computed Default Value

2.5. orElseThrow(Supplier<? extends Throwable> exceptionSupplier) - 예외 던지기

Optional<String> opt = Optional.empty();
String value = opt.orElseThrow(() -> new IllegalStateException("Value not found"));

3. Optional 변환 및 필터링

3.1. map(Function<? super T, ? extends U> mapper) - 값 변환

Optional<String> opt = Optional.of("Hello");
Optional<Integer> lengthOpt = opt.map(String::length);
System.out.println(lengthOpt.orElse(0)); // 5

3.2. flatMap(Function<? super T, ? extends Optional<U>> mapper) - 중첩 Optional 해제

Optional<String> opt = Optional.of("Hello");
Optional<Integer> flatMapped = opt.flatMap(str -> Optional.of(str.length()));
System.out.println(flatMapped); // Optional[5]

3.3. filter(Predicate<? super T> predicate) - 조건 필터링

Optional<String> opt = Optional.of("Hello");
Optional<String> filteredOpt = opt.filter(s -> s.startsWith("H"));
System.out.println(filteredOpt.orElse("No match")); // Hello

4. Optional 활용 예제

4.1. 기존 방식 vs Optional을 활용한 방식

기존 null 체크 방식

public String getUserName(User user) {
    if (user != null) {
        Profile profile = user.getProfile();
        if (profile != null) {
            return profile.getName();
        }
    }
    return "Unknown";
}

Optional을 활용한 방식

public String getUserName(User user) {
    return Optional.ofNullable(user)
            .map(User::getProfile)
            .map(Profile::getName)
            .orElse("Unknown");
}

5. 주의사항

  • Optional<T>은 필드로 사용하지 말 것: Optional은 리턴 타입으로만 사용해야 하며, 필드나 매개변수로 사용하면 불필요한 객체 생성이 발생할 수 있습니다.
  • 성능 고려: Optional은 null 체크를 간편하게 해주지만, 불필요하게 사용하면 객체 생성 비용이 발생할 수 있습니다.

6. 결론

  • Optional<T>은 null을 안전하게 처리할 수 있도록 도와주는 클래스.
  • orElse(), orElseGet(), orElseThrow() 등을 활용하여 기본값 처리 가능.
  • map(), flatMap(), filter() 를 사용하여 값 변환 및 필터링 가능.
  • 무분별한 사용을 지양하고, 리턴 타입으로 활용하는 것이 가장 적절함.

➡ Optional을 올바르게 활용하면 코드가 간결해지고 NullPointerException을 방지할 수 있음! 

728x90