[java] Optional 사용
Optional
-
java 8 에 추가
-
있거나 없는 값 표현
-
null 대체
생성
-
Optional.of()
: null 이 아닌 값
Optional<String> opt = Optional.of("value");
Optional.of(null) -> NullPointerException !
-
Optional.ofNullable()
: null이 가능한 값으로 생성
Optional<String> opt = Optional.ofNullable(someValue);
-
Optional.empty()
: 빈 값
Optional<String> opt1 = Optional.empty();
Optional<String> opt2 = Optional.ofNullable(null);
조회
-
get()
-
값이 없는 Optional에 get() 을 실행하면
NoSuchElementException
발생
-
Optional<String> opt = Optional.of("value");
String str = opt.gt(); // str: "value"
Optional<String> opt1 = Optional.empty();
opt1.get(); // NoSuchElementException
값 존재 확인
-
isPresent()
: 값이 있는지 확인 -
isEmpty()
: 값이 비었는지 확인 (java 11)
Optional<String> opt = Optional.of("value");
opt.isPresent(); // true
opt.isEmpty(); // false
Optional<String> opt1 = Optional.empty();
opt`.isPresent(); // false
opt`.isEmpty(); // true
값이 있으면 실행
-
ifPresent()
: if 문
String value1 = getValue1();
if (value1 != null) {
doSome(value);
}
// change..
Optional<String> opt1 = getValue();
opt1.ifPresent(value1 -> doSome(value1));
-
ifPresentOrElse()
: if-else 문
String value2 = getValue();
if (value2 != null) {
doSome(value2);
} else {
doOther();
}
// change..
Optional<String> opt2 = getValue();
opt2.ifPresentOrElse(
value2 -> doSome(value2),
() -> doOther()
);
값이 없을 때 다른 값 사용
String value = getValue();
String result = value == null ? "default" : value;
-
orElse()
-
값이 있으면 그 값을 return
-
값이 없으면 인자로 전달한 값 전달 (아래 예제에선
default
return)
-
Optional<String> opt = getValue();
String result = opt.orElse("default");
// String result = opt.orElse(null);
-
orElseGet()
-
orElase
와 거의 동일하나 값일 없을 경우 값 대신에 실행할method
를 지정
-
Optional<String> opt = getValue();
// orElseGet(Supplier<? extends T>)
String result = opt.orElseGet(() -> "default");
-
or()
-
값이 없을 경우 사용할
Optional
return
-
Optional<String> opt = getValue();
// or(Supplier<? extends Optional<? extends T>>)
Optional<String> result = opt.or(() -> Optional.or("default"));
-
orElseThrow
-
값이 있으면 해당 값 return, 없으면
exception
발생
-
Member m = repository.findById("id");
if ( m == null) {
throw new NoMemberException();
}
m.doSomething();
// change..
Optional<Member> opt = repository.findByid("id");
Member m = opt.orElseThrow(() -> new NoMemberException());
m.doSomething();
map
-
map
에 전달 받은 함수를 실행해서 값을 변환한Optional
return -
map
은 값이 없으면 빈Optional
return
Member m = repository.findById("id");
LocalDate birth = m.getBirthday();
int passedDays = cal(birth);
// change...
Optional<Member> memOpt = repository.findByid("id");
Optional<LocalDate> birthOpt = memOpt.map(mem -> mem.getBirthday());
Optional<Integer> pdOpt = birthOpt.map(birth -> cal(birth));
// 한번에 변환
Optional<Integer> pdOpt2 = memOpt.map(mem -> mem.getBirthday()).map(birth -> cal(birth));
// 빈 Optionaal 은 map 으로 전달한 함수를 실행하지 않고 빈 Optional 리턴
Optional<String> empty = Optional.empty();
Optional<String> empty2 = empty.map(str -> str.toUpperCase());
// empty2.isEmpty() -> true
flatMap
-
flatMap
에 전달 받은 함수 이용 값을 변환한Optional
return-
flatMap
에 전달한 함수는return type
이Optional
-
// Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper)
Optional<Member> memOpt = repository.findByid("id");
Optional<LocalDate> birthOpt = memOpt.flatMap(mem -> Optional.orNullable(mem.getBirthday()));
Optional<Integer> pdOpt = birthOpt.flatMap(birth -> calOptional<birth));
// flatMap 은 map 을 사용하였을 경우 Optional<Optional<LocalDate>> 와 같은 자료형의 Optional 을 하나 뺴주는 역할.
filter
-
조건을 충족하면 값 그대로 return
-
조건을 충족하지 못하면 빈
Optional
return
String str = getStringValue();
if (str != null && str.length() > 3) {
System.out.println("str: " + str);
}
// change 1
Optional<String> strOpt1 = getStringValue();
Optional<String> filtered1 = strOpt.filter(str -> str.length() > 3);
filtered1.isPresent(str -> System.out.println("str1: " + str));
// change 2
Optional<String> strOpt2 = getStringValue();
Optional<String> filtered2 = strOpt
.filter(str -> str.length() > 3)
.ifPresent(str -> System.out.println("str2: " + str2));
두 개의 Optional 조합
-
예제 소스
Member m = repository.findByid("id");
if (m == null) { return null; }
Company c = getCompany(m);
if (c == null) { return null; }
Card card = createCard(m, c);
return card;
-
변환 1
Optional<Member> memOpt = repository.findByid("id");
Optional<Company> comOpt = memOpt.map(mem -> getCompaany(mem));
Optional<Card> card = memOpt.flatMap(
mem -> comOpt.map(com -> createCard(mem, com);
);
-
변환 2
Optional<Member> memOpt = repository.findByid("id");
Optional<Card> cardOpt = memOpt.flatMap(mem -> {
Optional<Company> comOpt = getCompanyOptional(mem));
return comOpt.map(com -> createCard(mem, com));
});
정리
-
isPresent()
사용하면 -> null 사용할 때 유사한 구조 -
대신
map
,flatMap
,filter
,orElse
,or
,ifPresent
등 익숙해지기 -
Optional
을 조금 더Optional
답게