[Java 기초] 스트림과 Optional

Updated:

배열, 컬랙션, 임의의 수 등이 스트림의 소스가 될 수 있다.

스트림의 생성 방법은 각 소스마다 비슷하기 때문에 컬렉션을 스트림으로 생성하는 방법만을 대표적으로 살펴보겠다.

Stream<T> Collection.stream()

stream() 은 해당 컬렉션을 소스로 하는 스트림을 반환한다.

List<Integer> list = Arrays.asList(1,2,3);

Stream<Integer> intStream = list.stream(); // list를 
소스로 하는 컬렉션 생성

스트림의 성격과 이점

기존의 컬렉션이나 배열을 스트림으로 변환해서 사용해서 얻는 이점은 다음과 같다.

  • 데이터 소스가 무엇이던 같은 방식으로 다룰수 있다. $($메서드가 통일됨)
  • 컬렉션, 배열이 담고 있는 데이터를 for 문과 iterator로 출력할 필요가 없다. $($stream.forEach$($) 사용.)
  • 스트림 내부 메서드를 연속해서 사용하면 데이터를 코드 한줄로 처리 할 수 있다.
  • 재사용성이 높다.

  • 스트림은 데이터 소스를 읽기만할 뿐 변경하지 않는다.
    • 스트림 연산 결과를 컬렉션이나 배열에 담아서 반환 할 수도 있다.
  • 스트림은 일회용이다.
  • 스트림은 작업을 내부 반복으로 처리한다.

스트림의 연산

중간 연산 - 연산 결과가 스트림인 연산. 연속해서 추가 중간 연산 가능.

최종 연산 - 연산결과가 스트림이 아님. 스트림의 요소를 소모해서 결과를 만듦. 한번만 사용 가능.

최종 연산이 수행되기 전까지는 중간 연산이 수행되지 않는다.

최종 연산이 수행되어야 비로소 스트림의 요소들이 중간 연산을 거쳐 최종 연산에서 소모된다.

map 연산

map() - 스트림의 요소 변환 연산

  • 스트림에 저장된 값 중에서 원하는 필드만 뽑아내는데 사용
  • 특정 형태로 타입을 변환 하는데 사용
// 매개변수에 T타입을 R타입으로 변환해서 반환하는 함수를 지정해야 한다.
Stream<R> map(Function<? super T, ? extends R> mapper)
List<Order> orders = orderRepository.findAll(new 
OrderSearch());

List<SimpleOrderDto> result = orders.stream()
     .map(o -> new SimpleOrderDto(o)) // Stream<Order> 
     -> Stream<SimpleOrderDto>
     .collect(toList());

flatMap() - Stream<T[]>를 Stream로 변환

  • 스트림의 요소가 배열, 혹은 map$($)의 연산결과가 배열인 경우 사용
  • 스트림의 스트림을 하나의 스트림으로 합칠때 사용

Stream<String[]> → map$($Arrays::stream) → Stream<Stream> $($X)

Stream<String[]> → flatMap$($Arrays::stream) → Stream $($O)

reduce 연산

T reduce(T identity, BinaryOperator<T> accumulator) {
		T a = identity; // 초기값
		
		for(T b : stream)
				a = accumulator.apply(a, b);

		return a;
}

스트림의 처음 두 요소를 가지고 연산한 결과를 가지고 그 다음 요소와 연산한다.

초기값$($identity)과 어떤 연산$($Binary Operator)으로 스트림의 요소를 줄여나갈지 결정

forEach 연산

void forEach(Consumer<? super T> action)

스트림의 요소를 출력하는 용도로 많이 사용된다.

ex) .forEach(System.out::println)

collect 연산

매개변수로 주어지는 컬렉터를 기준으로 스트림의 요소를 수집.

toList$($) - 스트림을 리스트로 변환

List<Order> orders = orderRepository.findAll(new 
OrderSearch());

List<SimpleOrderDto> result = orders.stream()
     .map(o -> new SimpleOrderDto(o)) // Stream<Order> 
     -> Stream<SimpleOrderDto>
     .collect(toList()); // 스트림을 List로 변환

Optional 클래스

Optional<T>

  • T타입의 객체를 감싸는 래퍼 클래스.
  • Optinal타입의 객체에는 모든 타입의 참조변수를 담을 수 있다.
public final class Optional<T> {

		private final T value; // T타입의 참조변수
		...
}

중요

최종 연산의 결과를 그냥 반환하지 않고 Optional 객체에 담아서 반환.

Optional 객체에 결과를 담아서 반환하면 널 체크를 위한 if문 없이도 NullPointerException이 발생하지 않는 간결한 코드를 작성할 수 있게 된다.

Optional 객체 생성

  • of$($)
  • ofNullable$($) $($참조 변수의 값이 null일 가능성이 있다면 사용)

of$($)는 매개변수 값이 null이면 NullPointerException 발생.

Optional<T>의 참조변수를 기본값으로 초기화할 때는 null 대신 empty() 사용.

Optinal 객체의 값 가져오기

  • get$($) $($객체에서 반환된 값이 null일 때 예외 발생.)
  • orElse$($) $($객체에서 반환된 값이 null일 때 “” 반환.)
    • orElseGet$($) - null을 대체할 값을 반환하는 람다식을 인자에 지정.
    • orElseThrow$($) - null일 때 지정된 예외를 발생시킨다.

Categories:

Updated:

Leave a comment