[JAVA] 람다와 스트림 ( Lambda & Stream ) ⑩

DongGyu Jung·2022년 5월 5일
0

자바(JAVA)

목록 보기
58/60
post-thumbnail

🏃‍♂️ 들어가기 앞서..

본 게시물은 스터디 활동 중에 작성한 게시물로 자바의 정석-기초편 교재를 학습하여 정리하는 글입니다.
※ 스터디 Page : 〔투 비 마스터 : 자바〕

*해당 교재의 목차 순서와 구성을 참고하여 작성하며
각 내용마다 부족할 수 있는 내용이나 개인적으로 궁금한 점은
추가적인 검색을 통해 채워나갈 예정입니다.



💥 최종 연산

최종 연산은
직전에 알아봤었던 중간연산과는 다르게
스트림 당 단 1번만 사용할 수 있다.

최종 연산은 스트림을 소모해서 결과를 만들어내기 때문에
최종 연산 후에는
스트림이 닫히게 되고 사용할 수 없게 되는 것이다.

반환값
즉, 결과는
중간연산과 같은 스트림이 아닌
" 단일 값 "(int, boolean 등) 이거나
스트림의 요소가 담긴 " 배열 / 컬렉션 "일 수 있다.


🔅 forEach()

스트림 단원을 공부하면서 꽤 많이 본 최종 연산 메서드일 것이다.

각 요소에 적용시키는 함수를 매개변수로 받는데
이전 중간 연산 메서드 중 " 중간 결과를 확인하는 peek() " 와는 달리

forEach()는 스트림을 소모하는 최종 연산으로
반환 타입은 void이며
주로 forEach(System.out::print) 등과 같이
요소 출력의 용도로 많이 쓰인다.

forEachOrdered()

병렬 스트림의 경우, " 순서보장 " _ 스트림을 parallel()로 처리할 때

void forEach( Consumer<? super T> action )
void forEachOrdered( Consumer<? super T> action )

🔅 조건 검사

말그대로 매개변수로 들어온 조건식에 대한 검사 결과를 반환하는 메서드들로

boolean allMatch( Predicate<? super T> Predicate )
boolean anyMatch( Predicate<? super T> Predicate )
boolean noneMatch( Predicate<? super T> Predicate ) // <-> allMatch
  • allMatch() : 모든 요소 만족 → true

  • anyMatch() : 하나라도 요소 만족 → true

  • noneMatch() : 모든 요소 불만족 → true

이 3가지 메서드가 있다.

※ 조건에 일치하는 " 요소 찾기 "

주로 Stream의 중간 연산인 filter()와 함께 사용되는데
" 조건에 일치하는 첫 번째 요소 "를 반환하는 findFirst()
" 조건에 일치하는 아무거나 요소 하나 "를 반환하는 findAny() 가 있다.

첫번째의 의의를 두는 findFirst()
" 직렬 스트림(sequential()) "에서 쓰이고

순서 관련없이 병렬로 처리하는
" 병렬 스트림(parallel()) "에서 findAny() 가 쓰인다.

// Optional<Student> stuStream
Optional<Student> result = stuStream.filter( s -> s.getTotalScore() <= 100).findFirst();
Optional<Student> result = stuStream.parallel().filter( s -> s.getTotalScore() <= 100).findAny();

🔅 reduce()

스트림의 요소를 하나씩 줄여가며 " 누적연산 (accumulate)"을 수행한다.
BinaryOperator<T> --(extends)--> BiFunction<U,T,U> 상속관계
-> 결국, BinaryOperator<T> == BiFunction<T,T,T>


  • 매개변수 : BinaryOperator<T> accumulator

reduce() 메서드는 다양한 형태로
오버로딩이 되어있다.

//기본적 
Optional<T> reduce( BinaryOperator<T> accumulator )
/*
- identity : 초기값
- accumulator : 이전 연산 결과 & 스트림 요소에 수행할 연산
- combiner : (병렬 스트림) 결과를 "합치는데 사용"할 연산
*/
// ★ 핵심
T reduce( T identity, BinaryOperator<T> accumulator )

// 입력값 2개 받는 BinaryFunction F.I의 연산 -> 
// combiner -> 합치기 연산 
U reduce( U identity, BiFunction<U, T, U> accumulator, BinaryOperator<U> combiner )

사실 Optional<T> reduce()T reduce()
같은 것이지만

Optional<T> reduce() 에 " 매개변수 identity가 없는 이유 "는


만약 비어있는 스트림일 경우엔

T reduce()는 초기값이 없을 때, identity 값을 반환하게 때문에 괜찮다.
그렇기 때문에 반환타입이 identity의 타입과 동일하고

하지만 초기값 지정이 없다면
null이 반환될 수가 있다.

그렇기 때문에 Optional<T>로 반환하게 되는 것이다.
따라서 " identity 매개변수를 입력하지 않을 경우 "
《결과를 담을 참조변수》의 타입은 Optional로 지정해주어야한다.


실제로 스트림 최종 연산 메서드들(아래 참고) 중
여러 값들을 누적 or 차례대로 계산해서 결과를 반환하는
count(), sum(), max(), min()과 같은 메서드들도

자세히 살펴보면
모두 reduce() 메서드를 통한 연산을 활용하는 구조이다.


🔆 최종 연산 메서드 모음 🔆
collect()Collector 내용 : [JAVA] 람다와 스트림 ( Lambda & Stream ) ⑪ 글 참고

중간 연산설명
void forEach( Consumer<? super T> action )
void forEachOrdered( Consumer<? super T> action ) : 순서 유지 _ 병렬 스트림 처리 시에 주로 이용
각 요소에 지정된 작업 수행
long count()스트림 요소 개수
Optional<T> max( Comparator<T> comparator )
Optional<T> min( Comparator<T> comparator )
최대 / 최솟값
Optional<T> findAny() : 아무거나 하나 _ 병렬 - filter()와 자주 사용
Optional<T> findFirst() : 첫번째 요소 - 직렬
스트림의 요소 하나 반환
boolean allMatch( Predicate<T> p ) : 모두 만족
boolean anyMatch( Predicate<T> p ) : 하나라도 만족
boolean noneMatch( Predicate<T> p ) : 모두 만족 X
모든 요소가 주어진 조건 만족 여부 확인
Object[] toArray()
A[] toArray( IntFinction<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 )
요소를 하나씩 줄여가면서(Reducing) 계산
R collect( Collector<T, A, R> collector )
R collect( Supplier<R> supplier, BiConsumer<R, T> accumulator, BiConsumer<R, R> combiner )
스트림 요소 수집
*주로 그룹화 / 분할 결과 컬렉션에 담아 반환할 때 싸용

0개의 댓글