Optional<T>은 “T타입의 객체”를 감사는 래퍼 클래스
- 그래서 Optional타입의 객체는 모든 타입의 객체를 담을 수 있다.
- java.util.Optional은 JDK1.8부터 추가되었다.
public final class Optional<T> {
private final T value; //T타입의 참조변수
...
}
최종 연산의 결과를 그냥 반환하지 않고 Optional객체에 담아서 반환을 하면 반환된 결과가 null인지 매번 if문으로 체크하는 대신 Optional에 정의된 메서드를 통해서 간단히 처리할 수 있다.
- Optional<T>를 이용하면, null 체크를 위한 if문 없이도 NullPointerException이 발생하지 않는 보다 간결하고 안전한 코드를 작성하는 것이 가능하다.
Optional<T> 객체 생성하기
Optional객체를 생성할 때는 of() 또는 ofNullable()을 사용한다.
Optional<String> optVal = Optional.of(str);
Optional<String> optVal = Optional.of("abc");
Optional<String> optVal = Optional.of(new String("abc"));
참조변수의 값이 null일 가능성이 있으면, of()대신 ofNullable()을 사용해야 한다.
- of()는 매개변수의 값이 null이면 NullPointerException이 발생한다.
Optional<String> optVal = Optional.ofNullable(null); //Ok Optional.empty
Optional<String> optVal = Optional.of(null); //NullPointerException 발생
Optional<T>타입의 참조변수를 기본값으로 초기화할 때는 empty()를 사용한다.
Optional<String> optVal1 = null; //널로 초기화는 바람직하지 않다.
Optional<String> optVal2 = Optional.<String>empty(); //빈 객체로 초기화
- null로 초기화는 가능하지만 empty()로 초기화 하는것이 바람직하다.
<aside> 💡 empty()는 제네릭 메서드라서 앞에 <T>를 붙였다. (추정 가능하므로 생략할 수 있다.)
</aside>
Optional<T>객체의 값 가져오기
Optional객체에 저장된 값을 가져올 때는 get()을 사용한다.
- 값이 null일 때는 NoSuchElementException이 발생한다. (orElas()로 대체할 값을 지정할 수 있다.)
String s1 = optVal1.get();//optVal1에 저장된 값을 반환한다. null이면 NoSuchElementException발생
String s2 = optVal1.orElse("a");//optVal1에 저장된 값을 반환한다 null일때는, ""를 반환
orElse()의 변형
- null을 대체할 값을 반환하는 람다식을 지정할 수 있는 orElseGet()
- null일 때 지정된 예외를 발생시키는 orElseThrow()
public T orElseGet(Supplier<? extends T> supplier)
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
사용방법
String s1 = optVal.orElseGet(String::new);// () -> new String();
String s2 = optVal.orElseThrow(NullPointerException::new);//널이면 예외발생
isPresent()
OPtional객체의 값이 null이면 false, 아니면 true를 반환한다.
if(str != null){
System.out.println(str);
}
if (Optional.ofNullable(str).isPresent()){ //null일 수 있으니까 ofNullable()
System.out.println(str);
}
ifPresent(Consumer<T> block)은 값이 있으면 주어진 람다식을 실행하고, 없으면 아무일도 안한다.
- ifPresent를 이용해서 위에 isPresent()를 간단하게 사용하는 방법
Optional.ofNullable(str).ifPresent(System.out::println);
참조변수 str이 null이 아니면 값이 출력되고, null이면 아무 일도 일어나지 않는다.
OptionalInt, OptionalLong, OptionalDouble
IntStream과 같은 기본형 스트림의 최종 연산의 일부는 Optional대신 기본형을 값으로 하는 OptionalInt, OptionalLong, OptionalDouble을 반환한다.
OptionalInt에 정의된 메서드
OptionalInt findAny();
OptionalInt findFirst();
OptionalInt reduce(IntBinaryOperator op);
OptionalInt max();
OptionalInt min();
OptionalDouble average();
반환타입이 Optional<T>가 아니라는 것을 제외하면 Stream에 정의된 것과 유사하다.
- 기본형 Optional에 저장된 값을 꺼낼 때 사용하는 메서드는 이름이 조금씩 다르다.
Optional클래스값을 반환하는 메서드
Optional<T> | T get() |
OptionalInt | int getAsInt() |
OptionalLong | long getAsLong() |
OPtionalDouble | double getAsDouble() |
OptionalInt는 래퍼 클래스와 비슷하게 정의되어 있다.
public final class OptionalInt {
...
private final boolean isPresent; //값이 저장되어 있으면 true
private final int value; // int타입의 변수
Primitive타입 int의 기본값은 0이므로 아무런 값도 갖지 않는 OptionalInt에 저장되는 값은 0일 것이다.
OptionalInt opt1 = OptionalInt.of(0); //OptionalInt에 0을 저장
OptionalInt opt2 = OptionalInt.empty(); //OptionalInt에 0을 저장
System.out.println(opt1.isPresent()); //true
System.out.println(opt2.isPresent()); //false
System.out.println(opt1.equals(opt2)); //false
저장된 값이 없는 것과 0이 저장된 것은 isPresent()를 통해서 구분이 가능하다.
- 0을 넣는것도 값이 있는거니까 참조변수를 빈 객체로 초기화할 때는 empty()를 사용하는게 맞는거 같다.
예제
Optional<String> optStr = Optional.of("hi");
Optional<Integer> optInt = optStr.map(String::length);
System.out.println(optStr.get());
System.out.println(optInt.get());
Integer result1 = Optional.of("123")
.filter(s -> s.length() > 0) //filter Predicate(0보다 큰애들만 거른다.)
.map(Integer::parseInt)
.get();
System.out.println(result1);
Integer result2 = Optional.of("")
.filter(s -> s.length() > 0) //없으니까 null일거고
.map(Integer::parseInt).orElse(-1); //orElse로 -1나오게
System.out.println(result2);
Optional.of("456")
.map(Integer::parseInt)
.ifPresent(x -> System.out.println(x));
OptionalInt opt1 = OptionalInt.of(0); //OptionalInt에 0을 저장
OptionalInt opt2 = OptionalInt.empty(); //OptionalInt에 0을 저장
System.out.println(opt1.getAsInt()); //0
// System.out.println(opt2.getAsInt()); //NoSuchElementException 발생
/*
hi
2
123
-1
456
0
*/
'책 > Java의 정석' 카테고리의 다른 글
[java] 래퍼(wrapper)클래스 && Number클래스 (0) | 2023.02.10 |
---|---|
[java] Object클래스 (0) | 2023.02.09 |
[java] String 클래스와 StringBuffer (0) | 2023.02.09 |
[java] 예외처리(3) (0) | 2023.02.07 |
[java] 예외처리(2) (0) | 2023.02.07 |