안녕하세요. 씨엔스입니다.

 

우리가 개발을 할 때 가장 많이 발생하는 예외 처리 중 하나가 바로 NullPointerException 이라 생각합니다.

Null 오류를 발생시키지 않기 위해서 지금까지는 분기처리를 통해 Null 체크 여부를 확인했는데,

자바 8 버전에서 나온 Optional 클래스를 통해 NPE 방지를 알아보도록 하겠습니다.

 

 

  • Java 8 버전 이전 null 예외처리 방식
1
2
3
4
5
6
7
8
9
10
11
class CodeRunner{
    public static void main(String[] args){
        List<String> names = null;
        List<String> list = getNames();         
        // null 인 경우
        if(list != null) {
            // next step
        }
    }
}
 
cs

ㅇㅇㅇㅇㅇ

기존에는 null이 발생하는 상황이 생길 경우 if문을 이용하여 null을 체크 하지만, 이와 같은 경우 코드의 가독성이 떨어지고 해당 객체가 null을 가질 수 있는 객체인지, 필수 값인지 직관적으로 알 수 있는 방법이 없어 오류를 찾더라도 해결하기에 어려움이 발생할 수 있었습니다.

 

  • Java 8 버전에 나온 Optional을 사용한 방식
1
2
3
4
5
6
7
8
9
10
class CodeRunner{
    public static void main(String[] args){
        List<String> list = getNames();
        // list 가 null 인지 아닌지 체크
        Optional <List<String>> optional = Optional.ofNullable(list);
        System.out.println(optional); // Optional.empty 
        System.out.println(optional.isPresent()); // false    
    }
}
 
cs

 

Java 8 버전에 처음 도입된 Optional은 값이 존재할 수도 있고, 아닐 수도 있는 값을 객체로 포장해주는 클래스입니다.

null 체크를 직접 할 필요가 없고 NPE가 발생할 가능성이 있는 값을 다룰 필요가 없다는 장점이 있습니다.

 

 

Optional 사용하기

 

  • Optional.empty() : 비어있는 Optional 객체 생성하기(return : Optional.empty)
1
Optional<String> opt = Optional.empty(); // 비어있는 Optional 객체를 생성
cs

 

  • Optional.of() : Null 값이 없는 Optional 객체 생성하기(값이 null 이면 NPE 발생)
1
Optional<String> opt = Optional.of("value 존재"); // 값이 존재하는 Optional 객체 생성(Optional[value 존재])
cs

 

  • Optional.ofNullable() : null 이거나 값이 있을 수 있는 객체를 생성한다. (null 여부를 확신할 수 없을 때)
1
2
3
// Optional의 value는 값이 있을 수도 있고 null 일 수도 있다. 
Optional<String> optional1 = Optional.ofNullable(null); 
Optional<String> optional2 = Optional.ofNullable("value 존재");
cs

 

 

Optional 값 체크하기

 

  • get() : Optional의 값을 가져오고, 비어있는 Optional 객체에 대해서는 NoSuchElementException 오류가 발생한다.
1
2
Optional<String> opt = Optional.of("value 존재");  // Optional 값이 존재
System.out.println(opt.get()); // return value 존재
cs

 

  • orElse() : 비어있는 Optional 객체에 대하여 orElse로 넘어온 값을 반환한다.
1
2
Optional<String> opt1 = Optional.empty(); // 빈 Optional 객체
System.out.println(opt1.orElse("value")); // return value
cs

 

  • orElseGet() : 비어있는 Optional 객체에 대하여 orElseGet로 넘어온 함수형 값을 통해 생성된 객체를 전달한다.
1
2
Optional<String> opt2 = Optional.empty(); // 빈 Optional 객체
System.out.println(opt2.orElseGet(() -> new String("새로운 값"))); // return value
cs

 

  • orElseThrow() : 비어있는 Optional 객체에 대하여 orElseThrow로 넘어온 함수형 값을 통해 오류를 발생시킨다.
1
2
Optional<String> opt3 = Optional.empty(); // 빈 Optional 객체
System.out.println(opt3.orElseThrow(RuntimeException::new)); // return value
cs

 

  • map() : Optional 객체의 값을 원하는 형태로 형변환을 할 수 있다.
1
2
Optional<String> opt = Optional.of("TEST"); // Optional 객체 값 존재할 경우
System.out.println(opt.map(String::length)); // Optional 객체의 형태를 변경
cs

 

  • filter() : filter 메소드의 인자로 받은 람다 식이 참이면 Optional 객체를 그대로 통과시키고 거짓이면 Optional.empty()를 반환해서 추가로 처리가 안되도록 한다.
1
2
Optional<String> opt = Optional.of("test");
System.out.println(opt.filter(v -> v.equals("TEST"))); // true : Optional[TEST] , false : Optional.empty
cs

 

 

정리

 

  1. Optional 객체를 사용할 경우 null을 선언할 필요가 없습니다.
  2. 반환하는 경우에만 사용하자.
  3. 상황에 맞게 사용해야한다. (남발하지말라, 오히려 독이 된다.)

 

아직 실무에서 적용해본 적이 없어 저도 미숙하기에 이렇게 정리를 하면서 공부해보았는데, 실제 소스에서의 null 처리를 Optional을 통해 진행해볼까 합니다.

감사합니다.

 

 

-참고자료

 

 

+ Recent posts