개발 공부/Java

Optional 클래스란?

애해 2021. 1. 21. 23:52
728x90

# Optional 클래스 등장배경

"null"이 될수도 있는 객체를 감싸고 있는 일종의 wrapper클래스로 JAVA8부터 등장했다. 
기존에는 NPE(NullPointerException 널포인터예외)가 발생하지 않도록 별도의 null처리가 필요했다. 이로 인해 코드 가독성과 유지보수성이 떨어진다는 문제가 발생되었다. 

public String getUserRole(User user) { 
   if(user != null) { 
      String role = user.getRole(); 
      return role;  
   } 
   return "guest"; 
} 

 

<기존의 null처리 방법 예시>

스칼라나 히스켈과 같은 함수형 언어들은 "존재할수도, 존재하지 않을 수도 있는 값"에 대해 별개의 타입을 가지고 다양한 API로 개발자의 간접적인 접근이 가능하도록 했는데 Optional은 이에 영향을 받아 등장한 클래스이다.

 

 

# Optional의 효과 

(1) NPE를 발생시키는 null을 직접 다루지 않아도 된다.
(2) 직접적인 null처리 생략(null처리를 Optional클래스에 위임)으로 인한 코드 가독성과 유지보수성 향상

 

 

# Optional 사용법

(1) 변수선언

Optional<User> maybeUser; // User 타입 객체를 감쌀 수 있는 Optional 타입의 변수

Optional<Role> optRole;  // Role 타입 객체를 감쌀 수 있는 Optional 타입의 변수

Optional<Order> order;   // Order 타입 객체를 감쌀 수 있는 Optional 타입의 변수

제네릭을 제공하기 때문에 명기한 타입 파라미터에 따라 감쌀 수 있는 개체의 타입이 결정된다. 

변수명은 "maybe", "opt"와 같은 접두어를 붙여 Optional타입의 변수임을 명확히 나타내기도 한다.

 

 

(2) 객체 생성

 

   1. Optional.empty()

Optional<User> maybeUser = Optional.empty();

 

null을 담고있는 Optional 객체를 얻어온다. 이 객체는 Optional내부적으로 미리 생성해놓은 싱글톤 인스턴스이다.

 

   2. Optional.of()

Optional<User> maybeUser = Optional.of(aUser);

 

null이 아닌 객체를 담고있는 Optional객체를 생성한다. null이 넘어올 경우 NPE가 발생하므로 주의가 필요하다.

 

   3. Optional.ofNullable(value)

Optional<User> maybeUser = Optional.ofNullable(aUser);

Optional<User> maybeNotUser = Optional.ofNullable(null);

 

null인지 아닌지 확신할 수 없는 객체를 담고있는 Optional객체를 생성한다. Optional.of()와 Optional.ofNullable(value)을 합쳐놓은 개념의 메소드이다. null일 경우 비어있는 Optional 객체를 얻어온다.

 

 

(3) 객체 접근


   1. get()
비어있는 Optional 객체에 대해서, NoSuchElementException을 던진다.


   2. orElse(T other)
비어있는 Optional 객체에 대해서, 넘어온 인자를 반환한다.

   3. orElseGet(Supplier<? extends T> other)
비어있는 Optional 객체에 대해서, 넘어온 함수형 인자를 통해 생성된 객체를 반환한다. 비어있는 경우에만 함수가 호출되기 때문에 orElse(T other) 대비 성능상 이점을 기대할 수 있다.

   4. orElseThrow(Supplier<? extends X> exceptionSupplier)
비어있는 Optional 객체에 대해서, 넘어온 함수형 인자를 통해 생성된 예외를 던진다.

   5. ifPresent(Consumer<? super T> consumer)
특정 결과를 반환하는 대신에 Optional 객체가 감싸고 있는 값이 존재할 경우에만 실행될 로직을 함수형 인자로 넘길 수 있다. 함수형 인자로 람다식이나 메소드 레퍼런스가 넘어올 수 있는데 비동기 메소드의 콜백 함수처럼 작동한다. 

Optional<String> maybeCity = getAsOptional(cities, 3); // Optional

maybeCity.ifPresent(city -> {

   System.out.println("length: " + city.length());
   
});

 


(4) 활용


Optional을 제대로 사용하려면, Optional을 최대 1개의 원소를 가지고 있는 특별한 Stream이라고 생각하면 좋다. Optional 클래스와 Stream 클래스 간에 직접적인 구현이나 상속관계는 없지만 사용 방법이나 기본 사상이 매우 유사하기 때문이다. Stream 클래스가 가지고 있는 map()이나 flatMap(), filter()와 같은 메소드를 Optional도 가지고 있다. 


   1. map()

public String getRoleOfUserFromGrade(Order order) { 

   return Optional.ofNullable(order) 
   
  	 .map(order::getUser) 
 
         .map(User::getRole) 
         
         .map(Role::getGrade) 
         
         .orElse("Guest"); 
         
}


   2.filter()

public Optional<Member> getUserIfOrderWithin(Order order, int min) { 

   return Optional.ofNullable(order) 
   
         .filter(o -> o.getDate().getTime() > System.currentTimeMillis() - min * 1000) 
         
         .map(Order::getUser); 
}

 

# Reference

www.daleseo.com/java8-optional-effective/

 

반응형

'개발 공부 > Java' 카테고리의 다른 글

객체지향 5대원칙(SOLID 원칙)  (0) 2021.01.20