티스토리 뷰

Java

Java8 New features #5 (Optional<T>)

§무명소졸§ 2020. 8. 31. 11:38

Optional 클래스는 Java 8 의 새로운 기능 중 마지막으로 작성할 내용이다. 자바8 이전에도 Google Guava 같은 유틸 라이브러리 지원을 받아 사용할 수 있었는데 자바 8에 와서는 공식적으로 지원하게 됐다. 오늘은 이 Optional 클래스에 대해서 간단하게 알아보자.

Optional<T> 무엇인가?

Optional 클래스는 Wrapping 클래스이다. 자바는 객체 지향 언어이기 때문에 모든 type 에 클래스를 제공한다. int, long, char 같은 Primitive data type 도 Integer 나 Long , Character 같은 Wrapping 클래스를 제공한다. 물론 목적의 차이가 있지만 값을 Wrapping 하거나 편의 메서드를 제공하는등 기능적으로 볼때는 비슷한 맥락이 있다. 아래는 Optional<T> 클래스의 사용 예제이다.

- getNameById

public Optional<String> getNameById(String id) {
        Map<String, String> names = new HashMap<>();
        names.put("a", "조조");
        names.put("b", "유비");
        names.put("c", "관우");
        
        //retirm Optional.of(names.get(id));
        return Optional.ofNullable(names.get(id));
    }

아이디를 입력받아 이름을 반환하는 메서드이다. 결과 값을 ofNullable 이라는 팩토리 메서드를 통해 Optional 클래스로 값을 Wrapping해서 반환한다. 기본 메서드로 of 를 제공하지만  ofNullable 메서드를 사용한 이유는 인자로 들어가는 값이 null 을 허용할 수 있게 하기 위해서이다. names map 에 존재하지 않는 id값을 요청할 경우 null 을 반환한다.

 

- caller

 public void caller(String id) {
        final Optional<String> name = getNameById(id);
        if (name.isPresent()) {
            System.out.println(name.get());
        } else {
            System.out.println("ID is not exist");
        }
    }

getNameById 메서드를 사용하는 메서드이다. 어느정도 코드를 이해할 수 있다면 Optional 클래스의 목적을 알 수 있을 것이다. id에 해당하는 값이 존재할 경우 이름을 출력하고 없을 경우 "ID is not exist" 라는 문자열을 출력한다. 위 코드에서 else 구문은 제외하고 람다 표현식을 이용하면 아래와 같이 더욱 간결하게 작성할 수 있다.

getNameById(id).ifPresent(System.out::print);

또는 Null 일경우 Exception 반환할 수 있게 아래와 같은 코드 작성도 가능하다.

String name = getNameById(id).orElseThrow(RuntimeException::new);

 

Optional<T> 왜 사용하는가?

Optional 클래스는 왜 사용할까?? 물론 품질 좋은 코드를 작성하기 위해서일 것이다. 하지만 품질 좋다는 말은 너무 추상적이고 실제로 가능 큰 이유는 NPE(Null Pointer Exception) 방어하기 위해서이다. NPE 는 예외의 왕이라고 할 만큼 개발 중에 제일 많이 접하게 된다. 또한 Compile 시에는 알수 없고 Runtime 시에 확인이 가능하기 때문에 NPE 처리를 잘 하기 위해서 고대로(?) 부터 늘 고민을 많이 해왔다. 그래서 자바 8 이전에도 Null 오브젝트 패턴이나 , Guava 의 Optional 같은 클래스를 이용해서 처리하는 방법이 코딩좀 한다는 분들 사이에서 사용됐다. 

한번 예제를 살펴보자. 위에서 작성한 getNamdById 메서드에서 반환된 이름의 길이를 알고 싶어서 아래와 같은 코드를 작성했다고 하자. 만약에 getNameByID 메서드가 Optional 클래스를 사용하지 않았다면 "d" 입력값은 null 이고 4라인에서 NPE 가 발생할 것이다.

String name1 = getNameById("a");
int len1 = name1.length();

String name2 = getNameById("d");
int len2 = name2.length(); // NPE 

 

그래도 조금 생각있는 개발자는 아래와 같이 null 체크를 할 것이다.

String name2 = getNameById("d");
if (name2 != null) {
	int len2 = name2.length(); // NPE 
}

만약에 특정 개발자가 공통으로 사용하게 될 메서드를 작성하고 배포한다면. 이러한 로직 구현의 차이는 Client(메서드 사용측을 Client라고 칭했다.)를 작성하는 개발자의 역량에 따라 차이가 날 것이다.

하지만 리턴값이 Optional 이면 값을 얻기 위해서 반드시 Null 체크를 해야된다. 여기서 Optional 클래스의 목적이 나타난다.  리턴값이 Opitonal 이라는 이유는 해당 메서드를 사용하는 Client 에게 해당 리턴 값은 Null 을 포함할 수 있으니 적절한 처리를 해야된다. 라는 메세지를 명시적으로 알려줄 수 있다. 

  getNameById(id).ifPresent(name -> {
  	final int length = name.length();
  	System.out.println("name length is =>"  + length);
  });

생각없이 코드를 작성하는 개발자도 NULL 체크 로직에 대해서 고민하게끔 강제하게 만든다.

어쩌면 리턴 타입을 Wrapping 해서 처리하는건 번거롭게 느껴질수 있다. 하지만 Optional 클래스는 NULL 체크를 위한 많은 편의 메서드를 제공하기 때문에 단단하고 가독성 높은 품질의 코드를 작성하기 위해서 적극적으로 사용하는게 좋을 것 같다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크