Optional
Optional은 Java 8 부터 도입 되었으며 이전 버전까지 Java 의 고질적인 문제였던 NullPointerException 을 해결하기 위해 등장하였습니다.
Optional 객체 생성
Optional 객체를 생성하기 위해서는 Optional.of/Optional.ofNullable/Optional.empty 이렇게 3가지 방법을 사용할 수 있습니다.
public class Main {
public static void main(String[] args) {
String str = "Hello";
Optional<String> ofOpt = Optional.of(str);
//null 값이 들어오는 경우 NullPointerException 이 발생하게 됩니다.
Optional<String> nullableOpt = Optional.ofNullable(str);
//null 값이 들어올 경우 예외 없이 빈 Optional 객체를 반환합니다.
Optional<String> emptyOpt = Optional.empty();
//비어있는 Optional 객체를 생성합니다.
}
}
Optional 메서드
isPresent() 객체가 존재하면 true 를 반환해 줍니다.
String str = "Hello";
Optional<String> nullableOpt = Optional.ofNullable(str);
System.out.println(nullableOpt.isPresent()); //true
get() 최종적으로 연산을 끝낸 후 객체를 반환합니다. 이때 값이 없다면 예외를 반환합니다.
String str = "Hello";
//값이 있는 경우
Optional<String> nullableOpt = Optional.ofNullable(str);
System.out.println(nullableOpt.get()); //Hello
//값이 없는 경우
nullableOpt = Optional.ofNullable(null);
nullableOpt.get();//NoSuchElementException
orElse(), orElseGet() 최종적으로 연산을 끝낸 후에도 객체가 비어있다면 다른 제공할 객체를 지정하여 반환합니다. orElse 와 orElseGet 은 매우 유사하지만 orElseGet 메서드는 매개변수로 Supplier 를 받으며 Optional 에 값이 없을 경우에만 실행된다고 합니다.(orElse 는 값이 있던 없던 무조건 실행)
String str = "Hello";
String noValue = null;
//orElse
String s = Optional.ofNullable(noValue).orElse(str);
System.out.println(s); //Hello
//orElseGet
String s = Optional.ofNullable(noValue).orElseGet(() -> str);
System.out.println(s);//Hello
orElseThrow() 최종적으로 연산을 끝낸 후에도 값이 없을 경우 예외를 지정하여 던져줄 수 있습니다.
String str = "Hello";
String noValue = null;
Optional.ofNullable(noValue).orElseThrow(() -> new MyException("값을 입력해 주세요"));
ifPresent() 값이 존재하는 경우 동작을 지정하여 실행시켜 줍니다.
String str = "Hello";
String noValue = null;
Optional.ofNullable(str).ifPresent(System.out::println); //Hello
flatMap() Optional 구조로 감싸진 객체를 단일 요소로 만들어 줍니다.
class User {
private String name;
private int age;
//나이가 null 일지도 모른다고 가정해서 Optional 로 감쌌다.
public Optional<Integer> getAge() {
return Optional.ofNullable(age);
}
}
public class Main {
public static void main(String[] args) {
//Optional[Optional[0]] - map 사용시
System.out.println(Optional.ofNullable(new User()).map(User::getAge));
//Optional[0] - flatMap 사용시
System.out.println(Optional.ofNullable(new User()).flatMap(User::getAge));
}
}
Optional 사용의 올바른 예
if문 + isPresent() + get() 대신 orElse()/orElseGet() 을 사용하여 코드를 더욱 깔끔하게
String str = "Hello";
Optional<String> ofOpt = Optional.ofNullable(str);
//bad
if(ofOpt.isPresent()) {
System.out.println(ofOpt.get());
} else {
System.out.println("null");
} //Hello
//good
System.out.println(ofOpt.orElse(null)); //Hello
Optional 을 제너릭 타입에 맞춰야 할 경우가 아니라면 Optional 대신 OptionalXXX 타입을 사용할 것을 권장
//soso
Optional<Integer>.of(123);
//good
OptionalInt.of(123);
OptionalDouble.of(10.0);
OptionalLong.of(10L);
Optional 을 필드로 사용하지 말기
//bad
class User {
private String name;
private Optional<Integer> age;
}
//good
class User {
private String name;
private int age;
public OptionalInt getAge() {
return OptionalInt age;
}