본문 바로가기
JAVA/[JAVA] Stream

Optional

by oncerun 2022. 10. 12.
반응형

Stream의 종결처리 부분을 이해하기 위해선 Optional대한 이해가 필수적이며 Optional은 대한 이해는 범용적으로 필수적이다. 

 

NPE는 Null 상태인 오브젝트를 참조할 때 발생합니다. 

 

이는 언체크 예외를 반환하기 때문에 런타임에 발생합니다. 따라서 컴파일 시점에 발견할 수 없습니다.

 

Optional Class는 Null일수도 아닐 수도 있는 Object를 담은 객체입니다.

 

Optional을 만들기 위해선 다음과 같은 static method를 사용할 수 있습니다.

public static <T> Optional<T> of(T value);
public static <T> Optional<T> empty();
public static <T> Optional<T> ofNullable(T value);

static 키워드로 선언된 메서드는 컴파일 시 정적으로 바인딩되기 때문에 인스턴스화 없이 바로 사용할 수 있습니다. 

 

  • of() : Null이 아닌 오브젝트를 이용해 Optional을 만들 때 이용합니다. 인자로 Null을 넘길 시 에러가 발생합니다.
  • empty() : 빈 Optional을 만들 때 사용합니다.
  • ofNullable : Null인지 아닌지 모를 오브젝트로 Optional을 만들 때 이용합니다. 

 

String notNull = "notnull";
String isnull = null;

Optional<String> notNull1 = Optional.of(notNull);   //null이 아닌 값을 넣어야 함
Optional<String> empty = Optional.empty(); //비어 있는 Optional 객체 생성
Optional<String> isNull1 = Optional.ofNullable(isnull); // 널인지 아닌지 모를 때
Optional<String> isNotNull = Optional.ofNullable(notNull); //널인지 아닌지 모를 때

 

-- 22-10-12 s

 

분명 해당 객체가 Null을 반환하지 않는다는 확신이 있다면 Optional 유형을 사용하는 것보다는 미리 정의된 유형을 사용하는 것이 가독성을 더 높여준다고 생각합니다. 

 

하지만 100%라는 생각은 너무 위험한 생각이기에 변수명에 의미를 최대한 담고 사용하는 것이 안전하다고 봅니다. 

 

여기서 하나의 의문점이 들 수 있습니다. 

 

Optional의 of 메소드는 null이 들어오는 순간 NullPointException을 발생시킵니다. 따라서 이를 사용하는 것은 안전하지 않을 수 있는데 of 메서드를 사용하게 되는 순간이 있는지 의문이 들었습니다. 

 

이 의문에 대한 해답은 가정이 잘못되었다는 것 입니다.

 

이는 NullPointException을 발생시키는 코드가 그렇지 않은 코드보다 잘못되었다는 가정에 근거하는데, 이는 잘못된 가정입니다. 

 

이는 작성된 알고리즘 상 null을 발생시키면 안 되지만 null이 발생되었다는 알고리즘의 실패를 확인할 수 있는 좋은 코드로 이어질 수 있습니다. 

 

이를 ofNullable() 메서드를 통해 애매하게 넘어간다면 오류를 놓칠 수도 있는 환경을 만들게 되어 더 큰 재앙에 부딪칠 수 있기 때문입니다. 

 

 

-- 22-10-12 e

 

Optnional로 값을 확인하고 추출하는 방법

public boolean isPersent();

public T get();

public T orElse(T other);

public T orElseGet<Supplier<? extends T> supplier)

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X
  • isPresent : 안의 오브젝트가 null인지 아닌지 확인합니다. Null이 아닌 경우 true를 반환합니다.
  • get : Optional의 값을 추출합니다.  해당 값이 Null인 경우 에러를 발생합니다.
  • orElse : Optional이 null이 아니라면 Optional 안의 값을 null이라면 other로 공급된 값을 리턴합니다.
  • orElseGet : Optional이 null이 아니면 Optional 안의 값을 null이라면 supplier로 공급되는 값을 리턴합니다.
  • orElseThrow : Optional이 null이 아니라면 Optional 안의 값을, null이라면 excetpionSupplier로 공급되는 Exception을 던집니다.

 

Stream의 종결처리 Optional의 사용

public void ifPresent(Consumer<? super T> action)

public <U> Optional<U> map(Function<? super T, ? extends U> mapper)

public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper)
  • ifPresent : Optional이 null이 아니라면 action을 실행합니다.
  • map : Optional이 null이 아니라면 mapper를 실행합니다. 함수에서 리턴되는 타입과  Optional <U> 타입이 변경됩니다.
  • flatMap : mapper의 리턴 값이 또 다른 Optional이라면 한 단계의 Optional로 줄여 줍니다. Stream의 flatmap과 동일합니다. 

 

Stream에서 종결처리를 간단히 진행해보자.

 

Max / Min / Count는 Stream안에 있는 값의 최댓값, 최솟값, 데이터의 개수를 반환한다. 

다만 Stream이 비어있다면 빈 Optional을 반환한다.

Optional<T> max(Comparator<? super T> comparator);

Optional<T> min(Comparator<? super T> comparator);

long count();

 

Max와 Min은 데이터의 비교를 위해 Comparator를 인자로 받습니다.

리턴 타입이 Optional인 이유는 스트림이 비어있다면 최대, 최솟값을 구할 수 없기 때문입니다.

 

Optional<Integer> max = Stream.of(1, 2, 3, 4, 5)
        .max((x, y) -> x - y);
log.info("max value {}", max.get());

List<User> users = createUser();

User firstUser = users.stream()
        .min((user1, user2) -> user1.getName().compareTo(user2.getName()))
        .get();
log.info(" firstUser {}", firstUser);

long count = Stream.of(-1, -2, 3, 56, -53)
        .filter(x -> x > 0)
        .count();
log.info("count {}", count);

 

스트림과 Optional을 통해 종결처리를 할 수 있다.

Order order = createOrder()
        .stream()
        .filter(Order::isError)
        .max((x, y) -> x.getAmount().compareTo(y.getAmount()))
        .orElseThrow(() -> new IllegalArgumentException("Stream is null"));
log.info("Error Expensive Order {}", order);

 

반응형

'JAVA > [JAVA] Stream' 카테고리의 다른 글

[Java] Functional extends  (0) 2022.02.17
Stream (3)  (0) 2022.02.16
Stream (2)  (0) 2022.02.15
Stream  (0) 2022.02.12
Method Reference  (0) 2022.02.09

댓글