자바

[자바 개념] stream

라임온조 2023. 1. 13. 16:49

1. 스트림의 개념

자바 8부터 추가된 컬렉션과 배열의 저장 요소를 하나씩 참조해서 람다식(함수적 스타일)으로 처리할 수 있도록 해주는 반복자

 

2. 스트림의 특징

1) 람다식으로 요소 처리 코드를 제공한다

스트림이 제공하는 대부분의 요소 처리 메소드는 함수적 인터페이스 매개 타입을 가지기 때문에 람다식 또는 메소드 참조를 이용해서 요소 처리 내용을 매개값으로 전달할 수 있다

ArrayList<Integer> arrayList = new ArrayList<Integer>();
Stream<Integer> stream = arrayList.stream();
stream.forEach( s -> System.out.println(s));

 

2) 내부 반복자를 사용하므로 병렬 처리가 쉽다

외부 반복자

개발자가 코드로 직접 컬렉션의 요소를 반복해서 가져오는 코드 패턴을 말한다. 예를 들어, for문이나 while문을 작성하는 것이 있다. 

내부 반복자

컬렉션 내부에서 요소들을 반복시키고, 개발자는 요소당 처리해야 할 코드만 제공하는 패턴을 말한다.

내부 반복자를 사용하면 좋은 점

  • 컬렉션 내부에서 어떻게 요소를 반복시킬 지는 컬렉션에게 맡기고, 개발자는 요소 처리 코드에만 집중할 수 있다
  • 요소들의 반복 순서 변경, 멀티 코어 cpu를 최대한 활용하기 위해 요소들을 분배시켜 병렬 작업 할 수 있도록 도와줌

병렬 처리

  • 한 가지 작업을 서브 작업으로 나누고, 서브 작업들을 분리된 스레드에서 병렬적으로 처리하는 것
  • 병렬 처리 스트림을 이용하면 런타임 시 하나의 작업을 서브 작업으로 자동으로 나누고, 서브 작업의 결과를 자동으로 결합해서 최종 결과물을 생성한다.

3) 스트림은 중간 처리와 최종 처리를 할 수 있다

스트림은 컬렉션의 요소에 대해 중간 처리와 최종 처리를 수행할 수 있다.

중간 처리

매핑, 필터링, 정렬을 수행

최종 처리

반복, 카운팅, 평균, 총합 등의 집계 처리를 수행

ArrayList<Integer> arrayList = new ArrayList<Integer>();
arrayList.stream()
.mapToInt(Integer :: intValue) // 중간처리 - 값 뽑아내서 매핑
.average() // 최종 처리 - 평균 구하기

3. 스트림의 종류

BaseStream
Stream IntStream LongStream DoubleStream
  • BaseStream 인터페이스를 부모로 해서 자식 인터페이스들이 상속 관계를 이루고 있다
  • BaseStream 인터페이스에는 모든 스트림에서 사용할 수 있는 공통 메소드들이 정의되어 있을 뿐 코드에서 직접적으로 사용되지는 않는다. Stream, IntStream, LongStream, DoubleStream이 실제로 이용된다

Stream

객체 요소 처리

IntStream

int 처리

LongStream

long 처리

DoubleStream

double 처리

 

4. 스트림 얻기

리턴 타입 메소드(매개 변수) 소스
Stream<T> java.util.Collection.stream() 컬렉션
Stream<T>
IntStream
LongStream
DoubleStream
Arrays.stream(T[]), Stream.of(T[])
Arrays.stream(int[]), IntStream.of(int[])
Arrays.stream(long[]), LongStream.of(long[])
Arrays.stream(double[]), DoubleStream.of(double[])

배열

 

1) 컬렉션으로부터 스트림 얻기

ArrayList<Student> studentList = Arrays.asList(
	new Student("홍길동", 10),
    new Student("신용권", 20)
   );

Stream<Student> stream = studentList.stream();
stream.forEach(s -> System.out.println(s.getName()));

2) 배열로부터 스트림 얻기

String[] strArray = {"홍길동", "신용권"};
Stream<String> strStream = Arrays.stream(strArray);
strStream.forEach(a -> System.out.println(a));

5. 스트림 파이프라인

  • 대량의 데이터를 가공해서 축소하는 것을 리덕션이라고 한다. 데이터의 합계, 평균값, 카운팅, 최댓값 등이 대표적인 리덕션 결과물이다.
  • 컬렉션의 요소를 리덕션의 결과물로 바로 집계할 수 없을 경우에는 집계하기 좋도록 필터링, 매핑, 정렬, 그룹핑 등의 중간 처리가 필요하다.

1) 중간 처리와 최종 처리

스트림은 데이터의 중간처리와 최종 처리를 파이프라인으로 해결한다

파이프라인은 여러 개의 스트림이 연결되어 있는 구조를 말한다

스트림 소스(컬렉션, 배열 등) 오리지날 스트림 필터링 처리 중간 스트림(중간처리) 매핑 처리 중간 스트림(중간처리) 집계 처리 결과물(최종처리)
  • 최종 처리를 제외하고는 모두 중간 처리 스트림이다
  • 중간 스트림이 생성될 때 요소들이 바로 중간 처리 되는 것이 아니라 최종 처리가 시작되기 전까지 중간 처리는 지연된다. 최종 처리가 시작되면 컬렉션의 요소가 하나씩 중간 스트림에서 처리되고 최종 처리까지 오게 된다
  • 스트림 인터페이스에는 필터링, 매핑, 정렬 등의 많은 중간 처리 메소드가 있는데, 이 메소드들은 중간 처리된 스트림을 리턴한다. 그리고 이 스트림에서 다시 중간 처리 메소드를 호출해서 파이프라인을 형성하게 된다.
double ageAvg = list.stream() // 오리지날 스트림
.filter(m -> m.getSex() == Member.MALE) // 중간 처리 스트림
.mapToInt(Member :: getAge) // 중간 처리 스트림
.average() // 최종 처리
.getAsDouble();

2) 중간 처리 메소드

filter

필터링

mapXXX() 메소드

  • 매핑
  • 요소를 대체하는 요소로 구성된 새로운 스트림을 리턴한다.
원래 스트림 대체 과정 새로 생성된 스트림
B A A -> C
B -> D
D C
리턴 타입 메소드(매개 변수) 요소 -> 대체 요소
IntStream mapToInt(ToIntFunction<T>) T -> int
List<Student> studentList = Arrays.asList(
	new Student("홍길동", 10),
    new Student("신용권", 20)
   );
studentList.stream()
.mapToInt(Student :: getScore) // student 객체 타입을 getScore함수 실행 결과로 대체하는 스트림(여기서는 intStream) 리턴

distinct

스트림에서 중복되는 요소들을 모두 제거해주고 새로운 스트림을 반환

ArrayList<Integer> a = new ArrayList<Integer>();
a.stream().distinct(); // a에서 중복 제거한 Stream<Integer>을 return

3) 최종 처리 메소드

allMatch

매칭

average

집계

 

.... 추가: 병렬 처리 구체적, 각종 처리 메소드

'자바' 카테고리의 다른 글

[자바 개념] StringBuffer, StringBuilder  (0) 2023.02.06
[자바 개념] 자바 데이터 타입  (0) 2023.01.13
[자바 개념] switch  (0) 2023.01.12
[자바 개념] Math  (0) 2023.01.12
[자바 개념] 배열, Arrays, ArrayList  (0) 2023.01.11