JAVA 웹 개발 패키지 - 패스트캠퍼스/Chapter6

스트림(Stream) , reduce() 연산

giggs 2022. 1. 18. 11:22

 

스트림 이란?

 

  • 자료의 대상과 관계없이 동일한 연산을 수행
  • 배열, 컬렉션을 대상으로 연산을 수행함
  • 일관성 있는 연산으로 자료의 처리를 쉽고 간단하게 함
  • 자료 처리에 대한 추상화가 구현되었다고 함

 

  • 한번 생성하고 사용한 스트림은 재사용할 수 없음
  • 자료에 대한 스트림을 생성하여 연산을 수행하면 스트림은 소모됨(최종 연산이 이루어질 때 소모됨)
  • 다른 연산을 수행하기 위해서는 스트림을 다시 생성해야 함

 

  • 스트림 연산은 기존 자료를 변경하지 않음
  • 자료에 대한 스트림을 생성하면 스트림이 사용하는 메모리 공간은 별도로 생성되므로 연산이 수행돼도 기존 자료에 대한 변경은 발생하지 않음

 

  • 스트림 연산은 중간 연산과 최종 연산으로 구분됨
  • 스트림에 대해 중간 연산은 여러 개의 연산이 적용될 수 있지만 최종 연산은 마지막에 한 번만 적용됨
  • 최종 연산이 호출되어야 중간 연산에 대한 수행이 이루어지고 그 결과가 만들어짐
  • 따라서 중간 연산에 대한 결과를 연산 중에 알 수 없음 이를 '지연 연산'이라 함

 


 

배열 스트림 생성 ( doble / int / long 등 )


 

다양한 stream 중 IntStream 메서드 확인 ( 나머지도 비슷비슷하다)


 

다른 연산을 수행하기 위해서는 스트림을 다시 생성해야 함

 


 

중간 연산과 최종 연산

 

  • 중간 연산의 예 - filter(), map(), sorted() 등
  • 조건에 맞는 요소를 추출(filter)하거나 요소를 변환함(map)
  • 최종 연산이 호출될 때 중간 연산이 수행되고 결과가 생성됨
  • 문자열 리스트에서 문자열의 길이가 5 이상인 요소만 출력하기
  sList.stream().filter(s->s.length() >= 5).forEach(s->System.out.println(s));

filter()는 중간 연산이고, forEach()는 최종 연산임

 

  • 고객 클래스 배열에서 고객 이름만 가져오기
  customerList.stream().map(c->c.getName()).forEach(s->System.out.println(s));

map()은 중간 연산이고, forEach()는 최종 연산임

  • 중간 연산과 최종 연산에 대한 구현은 람다식을 활용함
  • 최종 연산의 예 - forEach(), count(), sum() 등
  • 스트림이 관리하는 자료를 하나씩 소모해가며 연산이 수행됨
  • 최종 연산 후에 스트림은 더 이상 다른 연산을 적용할 수 없음
  • forEach() : 요소를 하나씩 꺼내 옴
  • count() : 요소의 개수
  • sum() : 요소들의 합

 

~~. ~~. ~~ 점으로 이어져서 가독성은 떨어지지만 if, for문을 써야 한다던지 여러 가지  조건들이 있는 경우에도

한 줄로 표현 가능한 장점이 있다.

 


 

컬렉션 스트림 생성

 


중간 연산자와 최종 연산자 사용

 

 

새로운 연산을 수행하기 위해서는 기존의 스트림은 재사용할 수 없고 stream() 메서드를 호출하여 스트림을 다시 생성해야 함

 

람다식 - 가상 클래스와 가상 객체 존재하는 것이다.

 

 


 

연산 수행에 대한 구현을 할 수 있는 reduce() 연산

 

reduce() 연산

  • 정의된 연산이 아닌 프로그래머가 직접 구현한 연산을 적용
  • 최종 연산으로 스트림의 요소를 소모하며 연산을 수행
  • reduce() 메서드의 두 번째 요소로 전달되는 람다식에 따라 다양한 기능을 수행할 수 있음
  • 람다식을 직접 구현하거나 람다식이 긴 경우 BinaryOperator를 구현한 클래스를 사용함

 

reduce() 연산자

stream의 정해져 있는 중간 / 최종 연산 메서드가 아닌

프로그래머가 reduce() 한 BinaryOperator로 연산 사용하겠다.


연산 직접 구현 -

  • reduce() 메서드의 두 번째 요소로 전달되는 람다식에 따라 다양한 기능을 수행할 수 있음
  • 람다식을 직접 구현하거나 람다식이 긴 경우 BinaryOperator를 구현한 클래스를 사용함

 

람다식을 이용해서 - 스트림에서 제공되는 중간 연산 최종 연산 외에 - 프로그래머가 직접 연산을 구현할 수 있다.

reduce() 메서드에 2번째 파라미터 부분으로! 

 

람다식으로 구현 부분이 너무 길면 BinaryOperator를 구현하고 /  구현한 클래스로 인터페이스화 해주고 get  

 


 

 

review

Stream
배열과 컬렉션을 대상으로 연산을 수행
중간 연산과 최종 연산이 있고, 최종 연산이 호출될 때 수행되고 결과가 생성된다.
최종 연산 후에 스트림은 소모되는 개념으로 다른 연산에 적용할 수 없음 - 다시 생성해서 사용해야 됨
중간 연산과 최종 연산에 대한 구현은 람다식을 활용한다.
프로그래머가 직접 연산을 구현하는 reduce() 연산도 가능하다.

배열과 컬렉션에 대한 스트림을 만들고 람다식을 활용해
Stream(). - 중간 연산과 최종 연산을 사용하는 방법 
stream(). reduce() - 내가 직접 연산을 구현하여 사용하는 방법  - 실습하였다.

점점점(~.~.~.~)으로 이루어지는 코드가 한 번에 알아볼 수 있는 가독성은 떨어졌지만
복잡한 과정과 조건이 - 가상 내부 클래스 - 람다식 - 스트림의 개념으로 한 줄의 코드로 작성되었다.
Sream에 정해진 연산 외에도 여러 조건들을 내가 직접 구현해서 사용할 수 있었다.
이 부분은 큰 장점으로 앞으로 많이 사용될 거 같다.

Stream 은 메모리 공간을 별도로 생성해서 작업하고 소모되고 하는 것이라서
기존의 자료들에도 영향을 주지 않는 부분도 큰 장점인 것 같다.