@Test
public void test1(){
String str = null;
System.out.println(this.optionalTest(str));
}
@Test
public void test2(){
String str = "";
System.out.println(this.optionalTest(str));
}
@Test
public void test3(){
String str = "hello";
System.out.println(this.optionalTest(str));
}
private String optionalTest(String str){
str = Optional.ofNullable(str).orElse("hello world");
return str;
}
test1
"hello world"
test2
""
test3
"hello"
orElse 보다 orElseGet 을 지향하자!
orElse(...)에서 ...는 Optional 값 유무와 상관없이 무조건 실행된다.orElseGet(Supplier)에서 Supplier는 Optional에 값이 없을 때만 실행된다. 불필요한 오버헤드 없이 수행하기 위해서는 orElse() 대신 orElseGet()을 지향해야 한다.
// Bad
ItemDto itemDto = Optional.of(...)
.map(...)
.orElse(new ItemDto()); // Optional 값 유무와 상관없이 new ItemDto()는 무조건 실행됨 (생성 후 미사용 -> 불필요한 오버헤드)
// Good
ItemDto itemDto = Optional.of(...)
.map(...)
.orElseGet(ItemDto::new); // Optional 값이 없을 때만 new ItemDto()가 실행됨
Criteria.getItemCode() == null 일 때, new XXXException 발생
public void method() throws XXXException {
// validation
Optional.ofNullable(Criteria.getItemCode())
.orElseThrow(() ->
new XXXException("error.validation.field", new String[] { "에러" }));
}
Criteria.getItemCode() == null 일 때, new Exception 발생
public void method() throws Exception {
// validation
Optional.ofNullable(Criteria.getItemCode())
.orElseThrow(Exception::new)
.stream()
.forEach(reviewNo -> {
// for-each logic
});
}
public Json<?> getItem(Criteria Criteria) {
// 데이터 조회 (1)
Json<?> json = Optional.ofNullable(criteria)
.map((cri) -> { // cri: criteria
return feignClient.getItemInfo(cri.getItemCode(), cri.getItemName());
})
.orElse(new Json<>());
// 데이터 조회 (2)
List<Info> info = new ArrayList<>();
Optional.ofNullable(criteria)
.map((cri) -> { // cri: criteria
return (List<Map<String, Object>>) feignClient.getInfo(cri.getItemCode(), cri.getItemName()).getResult();
})
.orElse(Collections.emptyList())
.forEach((map) -> { // map: .map((cri)->{return ...})) 의 리턴 값 (컬렉션이라면 컬렉션 요소)
Info if = Info.builder()
.img(String.valueOf(map.get("img")))
.link(String.valueOf(map.get("link")))
.build();
info.add(if);
});
json.getResult().setInfo(info);
return json;
}
map 과 orElse
return Optional.ofNullable(criteria) // (0) 크리테리아
.map(this::getItem) // (1)
.map(OOORepository::selectItem) // (2)
.map((rep) -> {return ...;}) // (3)
.orElse("XXX");
(0) -> (1) -> (2) -> (3) 차례대로 흐름을 타며 중간에 (0) 크리테리아 또는 (1), (2), (3) 로직 중 하나라도 null이 리턴 된다면 orElse 문에 선언한 "XXX" 가 리턴된다. Info info = XXX;
Optional.ofNullable(json.getResult())
.ifPresent((result) -> { // result: json.getResult()
result.setInfo(info); // json.getResult() 가 null 이 아닐 때, 로직 수행
});
// json.getResult() 가 null 일 경우, NPE를 피하고 위 로직은 타지 않음