Optional
자바에서 원시 타입을 제외한 모든 참조 변수는 null을 가질 수 있어, 이로 인해 NullPointerException(NPE)이 빈번하게 발생한다.
public static void main(String[] args) {
String str = "abc";
if (str != null) {
System.out.println(str.toUpperCase()); // ABC
} else {
System.out.println("null");
}
}자바 8에서는 Optional 클래스를 도입하여 메서드 시그니처만 보고도 null 반환 가능성을 예측할 수 있게 하며, null 처리를 강제하는 효과를 준다.
Optional 객체 생성
Optional은 null이 될 수 있는 객체를 감싸는 래퍼 클래스로, null이 될 수 있는 객체를 담고 있는 Optional 객체를 생성할 수 있다.
public static void main(String[] args) {
Map<String, String> map = Map.of("existKey", "existValue");
Optional<String> opt1 = Optional.of(map.get("existKey")); // `null`이 아님을 보장할 때 사용
Optional<String> opt2 = Optional.ofNullable(map.get("notExistKey")); // `null`일 수도 있을 때 사용
Optional<String> opt3 = Optional.empty(); // `null`임을 명시적으로 나타낼 때 사용
}메서드
입력 값 null
입력 값 null 아님
Optional.of(T value)
NullPointerException 발생
Optional 객체 생성 (값을 담고 있음)
Optional.ofNullable(T value)
Optional.empty() 반환
Optional 객체 생성 (값을 담고 있음)
Optional.empty()
-(null을 담고 있는 Optional 객체 생성
-(null을 담고 있는 Optional 객체 생성
Optional 객체 조회
get() 메서드
get() 메서드Optional 객체에 담긴 값을 가져오기 위해서는 기본적으로 get() 메서드를 사용해서 가져올 수 있다.
public static void main(String[] args) {
Optional<String> opt = Optional.of("abc");
String str = opt.get();
System.out.println(str); // abc
}하지만 비어있는 Optional 객체에 get()을 호출하면 NoSuchElementException이 발생할 수 있기 때문에, ifPresent()와 결합하여 사용해볼 수 있다.
public static void main(String[] args) {
Optional<String> opt = Optional.empty();
if (opt.isPresent()) {
String str = opt.get();
System.out.println(str);
}
}하지만 위와 같은 방식은 if (value != null) { ... } 코드와 본질적으로 다르지 않으며, Optional의 장점을 활용하지 못한다.
올바른 Optional 값 조회 및 처리 방법
Optional 객체의 값을 조회하고 처리하는 위해 다양한 메서드가 제공된다.
ifPresent(Consumer<? super T> action)
Consumer 실행
아무 동작도 하지 않음
ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
Consumer 실행
Runnable 실행
orElse(T other)
값을 반환
전달 받은 인자를 반환
orElseGet(Supplier<? extends T> other)
값을 반환
Supplier를 실행한 결과를 반환
orElseThrow(Supplier<? extends X> exceptionSupplier)
값을 반환
Supplier가 제공하는 예외를 발생
public static void main(String[] args) {
// ifPresent
Optional<String> opt1 = Optional.of("abc");
opt1.ifPresent(s -> System.out.println(s.toUpperCase())); // ABC
// ifPresentOrElse
Optional<String> opt2 = Optional.empty();
opt2.ifPresentOrElse(s -> System.out.println(s.toUpperCase()),
() -> System.out.println("null")); // null
// orElse
String value1 = Optional.of("abc")
.map(String::toUpperCase)
.orElse("null"); // "ABC"
// orElseGet
String value2 = Optional.empty()
.map(String::toUpperCase)
.orElseGet(() -> "null"); // "null"
// orElseThrow
Optional<String> opt5 = Optional.empty();
String value = opt5.orElseThrow(IllegalArgumentException::new);
}orElse() vs orElseGet()
orElse() vs orElseGet()orElse()와 orElseGet()은 Optional이 비어있을 때 대체 값을 제공하는 동일한 기능을 가진 메서드지만, 기본값을 생성하는 시점에서 차이가 있다.
orElse(T other):Optional에 값이 있든 없든other객체가 항상 생성orElseGet(Supplier<? extends T> other):Optional에 값이 없을 때만Supplier람다식이 실행되어 기본값이 생성
때문에, 기본값 생성 비용이 큰 경우에는 orElseGet()을 사용하는 것이 성능상 유리하다.
Optional 활용 시 주의점
Optional은 남용하면 오히려 코드를 복잡하게 만들 수 있다.
메서드 반환 타입으로만 사용:
Optional은 메서드의 반환 타입(return type)으로 사용되는 것을 권장필드(멤버 변수)로 사용 금지: 클래스의 필드 타입으로
Optional을 사용하는 것은 권장되지 않음직렬화 문제, JPA 등에서의 비호환성 문제
메서드 매개변수로 사용 금지: 매개변수로
null을 보낼 수 있어Optional객체 자체가null이 될 수 있음메서드 오버로딩으로 해결하는 것이 더 나음
컬렉션 래핑 금지: 컬렉션은
null을 반환하기보다 비어있는 컬렉션(예:Collections.emptyList())을 반환하는 것을 권장
Last updated
Was this helpful?