# 클린코드, NULL을 반환하거나 인수로 전달하지 마라. 그리고 Java 8 Optional<T>
[Clean Code](http://book.daum.net/detail/book.do?bookid=BOK00022070866YE)에서 `NULL`의 사용에 대해서 다루는 내용이 있다. **7장 오류 처리**에서 **"NULL을 반환하지 마라"**, **"NULL을 전달하지 마라"**라는 소제목으로 소개하고 있다.
**클린코드**에서는 다음과 같은 예제를 소개한다.
```java:line-numbers
public void registerItem(Item item) {
if (item != null) {
ItemRegistry registry = peristentStore.getItemRegistry();
if (registry != null) {
Item existing = registry.getItem(item.getID());
if (existing.getBillingPeriod().hasRetailOwner()) {
existing.register(item);
}
}
}
}
```
> `null`을 확인하느라 바쁜 코드 예제
이런 코드의 경우 `null` 확인을 빼먹기라도 하면 혹시나 `null`인 객체를 사용하려고 할 때 `NPE(NullPointerException)`가 발생하게 된다. 책에서는 `null`외에 다른 특수한 목적의 객체를 반환하던가 `Collection`의 경우 비어있는 객체를 전달해서 `Collections.emptyList()`로 비어있음을 확인하는식의 방법을 추천하고 있다.
###
`null`을 반환하는것 뿐만 아니라 `null`을 인수로 전달하는 것도 피해야할 안티패턴이다. 결국 `null`을 반환하거나 전달하는 등의 패턴은 `NPE`의 늪에 우리를 빠뜨리게 할 여지가 다분하다. 그렇다면 `Java8`에서는 어떨까? `Optional`을 살펴보자.
###
***
# Java 8 Optional
> 1965년 **토니 호어**(Tony Hoare)는 **ALGOL W**라는 언어를 설계하면서 처음으로 `null` 레퍼런스 개념을 도입했다. 하지만 그는 여러 해가 지난 후 `null` 레퍼런스의 개념을 만든일이 **"억만 달러짜리 실수"**라고 표현했다.
> [Java 8 in Action]
`null`은 어찌보면 참 간편한 표현일 수 있다. 값이 없으면 그냥 `null`을 반환해 버리면 되니까 말이다. 하지만 이런식으로 `null`을 반환하는 메서드 종류가 늘어나면 코드는 점점 더 많은 중첩된 `if`구문 블록을 만들면서 들여쓰기 수준이 증가하고 `null`레퍼런스를 처리하기 위해 고군분투 해야만 한다.
###
`Java8`에서는 선택형값을 캡슐화하는 `java.util.Optional<T>`라는 새로운 클래스를 제공한다. `Optional<T>`을 이용하면 `null`레퍼런스 대신 값이 없는 상황을 표현할 수 있다.
###
예제를 만들어서 `Optional<T>`이 어떻게 사용되는지 확인해보자. 다음과 같은 클래스들이 있다고 설정하겠다.
- 사람 : 사람은 점심 도시락을 갖고 있거나 아닐수도 있다
- 점심 도시락 : 점심 도시락은 음료를 갖고 있을수도 있고 아닐수도 있다
- 음료 : 음료는 이름을 갖고 있다
> 이런 설정으로 하고 코드를 작성해보았다
## 기존의 `null` 레퍼런스 처리
```java:line-numbers
class Person {
private LunchBox lunchBox;
public LunchBox getLunchBox() {
return lunchBox;
}
}
class LunchBox {
private Beverage beverage;
public Beverage getBeverage() {
return beverage;
}
}
class Beverage {
private String name;
public String getName() {
return name;
}
}
```
별 문제가 없어보인다. 이 클래스들을 이용해서 만약 다음처럼 코드를 작성한다면 어떻게 될까?
```java:line-numbers
Person person = new Person();
String beverageName = person.getLunchBox().getBeverage().getName();
```
> `NullPointerException` 예외가 발생하는 코드
너무 당연하게도 `NPE`가 발생한다. **person**이 가지고 있는 **LunchBox**가 `null`이기 때문이다. 예외가 발생하지 않도록 보수적으로 수정한 코드는 다음과 같다.
```java:line-numbers
Person person = new Person(new LunchBox());
if(person.getLunchBox() != null) {
Beverage beverage = person.getLunchBox().getBeverage();
if (beverage != null) {
System.out.println(beverage.getName());
} else {
System.out.println("unknown");
}
}
```
> `null`인지 아닌지 `if`구문을 이용해 계속 확인하면서 코드를 진행해야 한다
있을지 없을지 모르는 **LunchBox**에 접근해서 있을지 없을지 모르는 **Beverage**의 이름을 출력하기 위해서 중첩된 `if`문이 사용되었고 들여쓰기 수준도 증가하고 있다. 이런 코드 진행은 가시성도 떨어질 뿐더러 실수를 유발할 가능성이 굉장히 높다.
## `Optional<T>` 사용
이제 `Java8`의 `Optional<T>`을 사용해보자. 위 예제 클래스들을 수정해보았다.
```java:line-numbers
class Person {
private Optional<LunchBox> lunchBox = Optional.empty();
public Optional<LunchBox> getLunchBox() {
return lunchBox;
}
}
class LunchBox {
private Optional<Beverage> beverage = Optional.empty();
public Optional<Beverage> getBeverage() {
return beverage;
}
}
class Beverage {
private String name;
public String getName() {
return name;
}
}
```
> 없을수도 있는 **LunchBox**와 **Beverage**를 `Optional<T>`로 감싸놓았다
위처럼 변경한 상태에서 음료의 이름에 접근하는 코드는 다음과 같다.
```java:line-numbers
Person person = new Person();
String beverageName =
person.getLunchBox()
.flatMap(LunchBox::getBeverage)
.map(Beverage::getName)
.orElse("unknown");
```
> **Person**이 **LunchBox**를 갖고 있으면 **LunchBox**의 **Beverage**에 접근한다. **Beverage**가 있으면 `Beverage::getName`을 통해 음료의 이름을 가져오고 없으면 **"unknown"**을 반환한다.
보는것 처럼 `Optional<T>`를 이용한 코드는 훨씬 명료할 뿐더러 `null` 을 확인하기 위한 복잡한 `if`구문도 없어서 가시성도 좋다. 반환값이나 인자를 `Optional<T>`로 감싸서 사용하게 되면 `null`체크를 위한 불필요한 코드를 줄일 수 있고 실수를 하게될 상황도 줄어든다.
###
예제를 통해서 **Optional**클래스를 사용해서 반환값이나 인자의 타입을 `null`을 사용하지 않는 코드를 살펴보았다. `Java8`의 새로운 **Optional** 클래스 덕분에 `null` 레퍼런스 참조의 문제를 해결하기 위해 특수목적객체나 새로운 wrapping 클래스를 만들 필요없이 `NPE`의 위협으로부터 안전해질 수 있게 된 것이다.
###
> 위 예시는 단순한 `Optional<T>`의 사용예를 보여준 것으로 `Optional<T>`의 모든 내용을 다룬것은 아니다. 위에서 사용한 메서드 외에도 **Optional**클래스는 다양한 메서드를 가지고 있다. [Java 8 - Optional Class](https://www.tutorialspoint.com/java8/java8_optional_class.htm)를 참고하기 바란다.