Java8에서 등장한 Optional 클래스, NULL로 인해 생기는 문제들을 얘로 해결해보자.

1
2
3
4
5
6
public class Ttest {
@Test
public Long test(Deal deal) {
return deal.getCategoryMapList().get(0).getCategoryTree().getCategoryGroup().getId();
}
}

어디서 NPE가 터질지 모른다.
아래와 같이 일일이 체크해야한다.

1
2
3
4
5
6
7
8
9
10
11
12
public class Ttest {
@Test
public Long test(Deal deal) {
if(deal == null) return null;
if(CollectionUtils.isEmpty(deal.getCategoryMapList())) return null;
if(deal.getCategoryMapList().get(0) == null) return null;
if(deal.getCategoryMapList().get(0).getCategoryTree() == null) return null;
if(deal.getCategoryMapList().get(0).getCategoryTree().getCategoryGroup() == null) return null;
if(deal.getCategoryMapList().get(0).getCategoryTree().getCategoryGroup().getId() == null) return null;
return deal.getCategoryMapList().get(0).getCategoryTree().getCategoryGroup().getId();
}
}

코드가 매우 구려졌다.
이를 그럼 자바 8스럽게, 우아하게 Optional로 처리해보자.

1
2
3
4
5
6
7
8
9
10
11
12
public class Ttest {
@Test
public Long test(Deal deal) {
return Optional.ofNullable(deal)
.map(deal -> CollectionUtils.isEmpty(deal.getCategoryMapList()) ? null : deal.getCategoryMapList())
.map(categoryMapList -> categoryMapList.get(0))
.map(categoryMap -> categoryMap.getCategoryTree())
.map(categoryTree -> categoryTree.getCategoryGroup())
.map(categoryGroup -> categoryGroup.getId())
.orElse(null);
}
}

if를 태우는 거보다 훨씬 가독성이 좋다고 생각한다.
Optional 체이닝 중에 중간에 null을 리턴하게 하면 orElse로 점프를 뛰게 된다.

아래와 같이 null이면 exception을 throw 할 수도 있다.

1
2
3
4
5
6
7
8
9
10
11
12
public class Ttest {
@Test
public void test(Deal deal) {
Optional.ofNullable(deal)
.map(deal1 -> CollectionUtils.isEmpty(deal1.getCategoryMapList()) ? null : deal1.getCategoryMapList())
.map(categoryMapList -> categoryMapList.get(0))
.map(categoryMap -> categoryMap.getCategoryTree())
.map(categoryTree -> categoryTree.getCategoryGroup())
.map(categoryGroup -> categoryGroup.getId())
.orElseThrow(() -> new IllegalArgumentException(deal.dealCategory.getCategory1()));
}
}

null을 핸들링 할 때 앞으로 자주 애용해야겠다.
JPA도 Optional로 리턴할 수 있으니 앞으로 Optional로 무조건 받아서 처리하자.

1
2
3
4
@Repository
public interface HotelRepository extends PagingAndSortingRepository<Hotel, Long> {
Optional<Hotel> findById(long id);
}