[Java] 스트림

2024. 8. 24. 21:34Java/람다와 스트림

자바 8부터 컬렉션 및 배열 요소를 반복 처리하기 위해 스트림을 사용할 수 있다. Stream은 Iterator과 비슷하지만 다음과 같은 차이점을 가지고 있다. 

 

1. 처리 속도가 빠르고 효율적이다. 

2. 람다식으로 다양한 요소 처리를 정의할 수 있다. 

3. 중간 처리와 최종 처리를 수행하도록 파이프 라인을 형성할 수 있다. 

 

내부 반복자

for문과 Iterator은 컬렉션 요소를 바깥쪽으로 반복해서 가져와 처리한다. 이를 외부 반복자라고 한다. 반면에 스트림은 컬렉션 내부로 주입시켜 요소를 반복 처리하는데 이를 내부 반복자라고 한다. 

내부 반복자는 멀티 코어 CPU를 최대한 활용하기 위해 요소를 분배시켜 병렬 작업할 수 있다. 

 

중간 처리와 최종 저리

스트림은 하나 이상 연결될 수 있다. 오리지널 스트림 뒤에 필터링 스트림이 연결될 수 있고, 그 뒤에 매핑 중간 스트림이 연결될 수 있다. 이러한 연결되어 있는 것을 스트림 파이프라인이라고 한다. 

중간 스트림은 최종 처리를 위해 요소를 걸러내거나(필터링), 요소를 변환시키거나(매핑), 정렬하는 작업을 처리한다. 최종 처리는 정제된 요소를 반복하거나, 집계 작업을 수행한다. 

 

스트림 파이프라인은 반드시 최종 처리 부분이 있어야 한다. 없다면 작동하지 않는다. 

 

스트림의 특징

스트림은 데이터 소스로부터 데이터를 읽기만 할 뿐, 데이터 소스를 변경하지 않는다. 또한 스트림은 일회용이다. 필요하다면 스트림을 다시 생성해서 사용해야 한다. 

 

스트림을 얻을 수 있는 메서드

 

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

List와 Set 인터페이스를 구현한 모든 컬렉션에서 객체 스트림을 얻을 수 있다. 

Stream<Product> stream = list.stream();
stream.forEach(p -> System.out.println(p));

 

배열에서 스트림 얻기

java.util.Arrays 클래스를 이용해서 배열 스트림을 얻을 수 있다. 

//String<String> strStream = Arrays.stream(strArray);
//strStream.forEach(item -> System.out.println(item + ",");
IntStream intStream = Arrays.stream(intArray);
intStream.forEach(item -> System.out.println(item + ",");

 

숫자범위로부터 스트림 얻기

range()의 첫번째 매개변수는 시작 수이고, 두 번째 매개값은 끝수 인데, 끝수를 포함하지 않으려면 range()를, 포함하면 rangeClose()를 사용한다. 

IntStream stream = IntStream.rangeClosed(1,100);
stream.forEach(a -> sum += a);

 

필터링

필터링은 요소를 걸러내는 중간 처리 기능이다. distinct()와 filter()가 있다. 

distinct는 메서드의 중복 요소를, filter은 Predicate가 true로 리턴하는 요소만 필터링한다. Predicate는 다음과 같은 종류가 있다. 

 

 

요소 변환

매핑은 스트림의 요소를 다른 요소로 변환하는 중간 처리 기능을 말한다. mapXXX메서드 종류는 다음과 같다.