# Table of Contents
# Optional API
Java 8부터 도입된 Optional API
를 사용하면 NullPointException
을 더 쉽게 핸들링할 수 있다.
# NullPointException
Java 언어로 개발을 할 때 가장 많이 발생하는 예외 중 하나가 바로 NullPointException
이다.
Person person = null;
person.getName();
Exception in thread "main" java.lang.NullPointerException at Main.main(Main.java:16)
NullPointException
을 피하기 위한 조건문은 코드를 지저분하게 한다.
Person person = null;
if (person != null) {
person.getName();
}
# Optional
Optional
은 Java 8에서 추가된 기능으로 null
이 올 수 있는 객체를 감싼 Wrapper 클래스다. 객체는 Optional의 value
속성에 저장된다.
public final class Optional<T> {
private final T value;
// ...
}
Optional을 다음과 같이 생성한다.
Person person = null;
Optional<Person> optional = Optional.ofNullable(null);
이제 null
이 아닐 때만 값에 접근할 수 있다.
optional.ifPresent(p -> p.getName());
이제 자세한 Optional 사용법에 대해 알아보자.
# Optional 생성하기
# Optional.empty()
empty()
는 값이 빈 Optional을 생성한다.
Optional<Person> optional = Optional.empty();
System.out.println(optional.isPresent()); // false
# Optional.of()
of()
에 null일 가능성이 없는 값을 전달하여 Optional을 생성한다.
Person p = new Person("Paul");
Optional<Person> optional = Optional.of(p);
System.out.println(optional.isPresent()); // true
of()
는 값이 없는 경우 NullPointException이 발생시킨다.
Person p = null;
Optional<Person> optional = Optional.of(p); // NullPointerException
# Optional.ofNullable()
ofNullable()
은 null일 가능성이 있는 객체를 전달하여 Optional을 생성한다.
Optional<Person> optional = Optional.ofNullable(null);
System.out.println(optional.isPresent()); // false
Person person = new Person("Paul");
Optional<Person> optional = Optional.ofNullable(person);
System.out.println(optional.isPresent()); // true
# Null 체크
Optional
클래스에는 Null 체크를 위한 메소드가 존재한다.
# isPresent()
isPresent()
를 사용하면 객체가 null인지 확인할 수 있다.
Optional<Person> optional = Optional.ofNullable(null);
System.out.println(optional.isPresent()); // false
Person person = new Person("Paul");
Optional<Person> optional = Optional.ofNullable(person);
System.out.println(optional.isPresent()); // true
# ifPresent()
ifPresent()
는 객체가 null이 아닐 때 람다식을 실행한다.
Person person = new Person("Paul");
Optional.ofNullable(person)
.ifPresent((p -> System.out.println(p.getName())));
Paul
객체가 null이면 람다식을 실행하지 않는다.
Person person = null;
Optional.ofNullable(person)
.ifPresent((p -> System.out.println(p.getName())));
# 값 가져오기, 예외 처리하기
# get()
get()
을 사용하면 Optional이 가지고 있는 객체를 가져올 수 있다.
String str = Optional.ofNullable("Hello").get();
만약 값이 없다면 NoSuchElementException
이 발생한다.
String str = Optional.ofNullable(null).get(); // NoSuchElementException
# orElse()
orElse()
는 Optional이 비어있다면 orElse()
로 지정한 값을 반환한다.
String str = "Something";
String value = Optional.ofNullable(str)
.orElse("Another thing");
System.out.println(value); // Something
String str = null;
String value = Optional.ofNullable(str)
.orElse("Another Thing");
System.out.println(value); // Another Thing
# orElseGet()
orElseGet()
는 Optional이 비어있다면 람다식을 실행하고 람다식의 반환값을 반환한다.
String str = "Something";
String value = Optional.ofNullable(str)
.orElseGet(() -> "Another thing");
System.out.println(value); // Something
String str = null;
String value = Optional.ofNullable(str)
.orElseGet(() -> "Another thing");
System.out.println(value); // Another thing
# orElseThrow()
orElseThrow()
는 Optional이 비어있다면 예외를 발생시킨다.
UserEntity user = userRepository.findOneByName(username)
.orElseThrow(() -> new UsernameNotFoundException(username));
메소드 참조를 사용할 수도 있다.
String str = "Something";
String value = Optional.ofNullable(str)
.orElseThrow(NoSuchElementException::new);
System.out.println(value); // Something
String str = null;
String value = Optional.ofNullable(str)
.orElseThrow(NoSuchElementException::new); // Exception in thread "main" java.util.NoSuchElementException
System.out.println(value);
# 필터링
filter()
을 사용하면 객체를 필터링할 수 있다.
Optional.of("ABCD")
.filter(v -> v.startsWith("AB"))
.ifPresent(value -> System.out.println(value));
ABCD
Optional.of("ABCD")
.filter(v -> v.startsWith("XY"))
.ifPresent(value -> System.out.println(value));
# 변환
# map()
map()
을 사용하면 객체를 변환할 수 있다.
Optional.of("ABCD")
.map(value -> value.toLowerCase())
.ifPresent(value -> System.out.println(value));
abcd
위 코드는 메소드 참조
을 사용하여 다음과 같이 단축할 수도 있다.
Optional.of("ABCD")
.map(String::toLowerCase)
.ifPresent(System.out::println);
# flatMap()
flatMap()
을 사용하면 다른 Optional로 반환할 수 있다.
Optional.of("ABCD")
.flatMap(value -> Optional.of(value.toLowerCase()))
.ifPresent(System.out::println); // abcd
# 원시타입 옵셔널
제너릭과 Wrapper 클래스를 사용하면 원시 타입의 옵셔널을 생성할 수 있다.
Optional<Integer> optional = Optional.of(1);
optional.ifPresent(System.out::println); // 1
그러나 제네릭과 Wrapper 클래스를 사용하지 않고도 원시 타입의 옵셔널을 생성할 수도 있다.
OptionalInt optional = OptionalInt.of(1);
optional.ifPresent(System.out::println); // 1
제공되는 원시 타입의 옵셔널은 다음과 같다.
- OptionalInt
- OptionalLong
- OptionalDouble