1. 스트림  연산과정에 필요한 3가지

1) 질의 대상이 되는 소스(컬렉션)

2) 파이프 라인에 해당하는 중간 연산자

3) 파이프 라인을 종료하고 결과를 출력하는 최종 연산자




중간 연산자


 연산

 반환값

연산 인수 

함수 디스크립터 

 filter

Stream<T>

 Predicate<T>

T -> boolean 

 map

Stream<T>

Function<T, R> 

T -> R 

 limit

Stream<T> 

 

 

 sorted

 Stream<T>

Comparator<T> 

(T, T) -> int 

distinct 

 Stream<T>

  

skip                            Stream<T>



<스트림의 중간 연산자>

Stream<T> distinct()        중복을 제거

Stream<T> filter(Predicate<T> predicate)     조건에 안 맞는 요소 제외

Stream<T> limit (long maxSize)         스트림의 일부를 잘라낸다

Stream<T> skip(long n)        스트림의 일부를 건너뛴다.

Stream<T> peek(Consumer<T> action)     스트림의 요소에 작업을 수행

Stream<T> sorted()

Stream<T> sorted(Comparator<T> comparator)     스트림의 요소를 정렬한다.


스트림의 요소를 변환한다.

Stream<R> map(Function<T,R> mapper)

DoubleStream mapToDouble(ToDoubleFunction<T> mapper)

IntStream mapToInt(ToIntFunction<T> mapper)

LongStream mapToLong(ToLongFunction<T> mapper)

Stream<R> flatMap(Function<T,Stream<R>> mapper)

DoubleStream flatMapToDouble(Function<T.DoubleStream> m)

IntStream flatMapToInt(Function<T, IntStream> m)

LongStream flatMapToLong(Function<T,LongStream> m)




<스트림의 최종 연산자>

void forEach(Consumer<? super T> action>

void forEachOrdered(Consumer<? super T>action)     각 요소에 지정된 작업 수행


long count()         스트림의 요소의 개수 반환


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

Optional<T> min (Comparator<? super T> comparator) 스트림의 최대값/최소값을 반환

스트림의 요소 하나를 반환

Optional<T> findAny() //아무거나 하나

Optional<T> findFirst() //첫번째 요소


주어진 조건을 모든 요소가 만족시키는지, 만족시키지 않는지 확인

boolean allMatch(Predicate<T> p) //모두 만족 하는지

boolean anyMatch(PredicaAte<T> p ) //하나라도 만족하는지

boolean nonMatch(Predicate<> p) //모두 만족하지 않는지


스트림의 모든 요소를 배열로 반환

Object[] toArray()    

A[] toArray(IntFunction<A[]> generator)


스트림의 요소를 하나씩 줄여가면서(리듀싱) 계산한다.

Optional<T> reduce(BinaryOperator<T> accumulator)

T reduce (T identity, BinaryOperator<T> accumulator)

U reduce (U identity, BiFunction<U,T,U> accumulator, BinaryOperator<U> combiner)


스트림의 요소를 수집한다. 주로 요소를 그룹화하거나 분할한 결과를 컬렉션에 담아 반환하는데 사용된다.

R collect(Collector<T,A,R> collector)

R collect(Supplier<R> supplier, BiConsumer<R,T> accumulator, BiConsumer<R,R> combiner)


연산 

비고 

 forEach

스트림에 각 요소를 람다를 통해 특정 작업을 실행한다. 

 count

스트림의 요소 개수를 반환한다. (long) 

collect 

스트림을 컬렉션 형태로 반환한다. 



**중간 연산은 map()과 flatMap(), 최종연산은 reduce()와 collect()가 핵심이다. 나머지는 이해하기 쉽고 사용법도 간단하다.

참고) Optional은 일종의 래퍼 클래스(wrapper class)로 내부에 하나의 객체를 저장할 수 있다.
출처: https://demoversion.tistory.com/27 [Demoversion]


*지연된 연산

스트림 연산에서 한 가지 중요한 점은 최종 연산이 수행되기 전까지는 중간 연산이 수행되지 않는다는 것이다. 스트림에 대해 distinct()나 sort()같은 중간 연산을 호출해도 즉각적인 연산이 수행되는 것은 아니라는 것이다. 중간 연산을 호출하는 것은 단지 어떤 작업이 수행되어야 하는지를 지정해주는 것일 뿐이다. 최종 연산이 수행되어야 비로소 스트림의 요소들이 중간 연산을 거쳐 최종 연산에서 소모된다.


Stream<Integer>와 IntStream

요소의 타입이 T인 스트림은 기본적으로 Stream<T>이지만, 오토박싱&언박싱으로 인한 비효율을 줄이기 위해 데이터 소스의 요소를 기본형으로 다루는 스트림, IntStream, LongStream, DoubleStream이 제공된다. 일반적으로 Stream<Integer>대신 IntStream을 사용하는 것이 더 효율적이고, IntStream에는 int타입의 값으로 작업하는데 유용한 메서드들이 포함되어 있다. 보다 자세한 것은 곧 설명한다.


*병렬 스트림

스트림으로 데이터를 다룰 때의 장점 중 하나가 바로 병렬 처리가 쉽다는 점이다. fork&join프레임워크로 작업을 병렬처리하는 것을 배웠는데, 병렬 스트림은 내부적으로 이 프레임워크를 이용해서 자동적으로 연산을 병렬로 수행한다. 우리가 할일이라고는 그저 스트림에 parallel()이라는 메서드를 호출해서 병렬로 연산을 수행하도록 지시하면 될 뿐이다.

반대로 병렬로 처리되지 않게 하려면 sequential()을 호출하면 된다. 모든 스트림은 기본적으로 병렬 스트림이 아니므로 sequential()을 호출할 필요가 없다. 이 메서드는 parallel()을 호출한 것을 취소할 때만 사용한다.


참고) parallel()과 sequential()은 새로운 스트림을 생성하는 것이 아니라, 그저 스트림의 속성을 변경할 뿐이다.


int sum = strStream.parallelStream() //strStream을 병렬 스트림으로 전환

.mapToInt(s -> s.length())

.sum();


앞서, 병렬처리가 항상 더 빠른 결과를 얻게 해주는것이 아니라는 것을 명심하자.


+ Recent posts