자바의 Optional 클래스는 null이 아닌(non-null) 값을 담거나 담지 않을 수도 있는 일종의 컨테이너 역할을 합니다. 이 클래스는 코드 곳곳에서 발생하는 NullPointerException을 줄이기 위해 Java 8에서 처음 도입되었습니다.
그리고 Java 9에서는 기본값(default value)을 더욱 편리하게 다룰 수 있도록 세 가지 메서드가 새롭게 추가되었습니다. 바로 ifPresentOrElse(), or(), 그리고 stream()입니다.
Optional에서 스트림 얻기
stream() 메서드는 Optional 객체에 값이 존재하면 그 값을 하나만 담은 스트림을 반환하고, 값이 비어 있다면 빈 스트림(empty stream)을 반환합니다. 덕분에 Optional을 기존의 스트림 API와 자연스럽게 연결해 사용할 수 있습니다.
특히 스트림 파이프라인 안에서 flatMap(Optional::stream) 형태로 활용하면 값이 존재하는 요소만 손쉽게 걸러낼 수 있어 매우 유용합니다.
예제 코드
아래 예제에서는 Person 클래스를 활용해 Optional 객체로부터 스트림을 얻어 처리하는 방법을 살펴보겠습니다.
import java.util.Optional;
import java.util.stream.Stream;
public class OptionalTest {
public static void main(String args[]) {
getPerson().stream()
.map(Person::getName)
.map("Jai "::concat)
.forEach(System.out::println);
getEmptyPerson().stream()
.map(Person::getName)
.map("Jai "::concat)
.forEach(System.out::println);
}
private static Optional<Person> getEmptyPerson() {
return Optional.empty();
}
private static Optional<Person> getPerson() {
return Optional.of(new Person("Adithya"));
}
static class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}실행 결과
Jai Adithya
코드 동작 원리
- getPerson():
Optional.of()를 사용해 "Adithya"라는 이름을 가진 Person 객체를 감싼 Optional을 반환합니다. 여기에stream()을 호출하면 Person 객체 하나를 포함하는 스트림이 생성되고, 이후map()연산을 통해 "Jai Adithya" 문자열이 만들어져 출력됩니다. - getEmptyPerson():
Optional.empty()로 빈 Optional을 반환합니다. 이 경우stream()은 빈 스트림을 반환하기 때문에 뒤따르는map()과forEach()연산은 아무것도 실행하지 않습니다. - 따라서 최종 출력 결과는 "Jai Adithya" 한 줄만 나타나게 됩니다.
이처럼 Java 9의 stream() 메서드를 활용하면 Optional의 값 존재 여부를 조건문으로 확인하지 않고도, 스트림 연산만으로 깔끔하고 안전하게 데이터를 처리할 수 있습니다.