@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를 피하고 위 로직은 타지 않음