1. 자바 8 Stream
- 스트림은 자바 8부터 추가된 컬렉션(배열 포함)의 저장 요소를 하나씩 참조해서 람다식(함수적 스타일)으로 처리할 수 있도록 해주는 반복자입니다.
- 자바 7 이전까지는 컬렉션을 순차적으로 처리하기 위해 Iterator 반복자를 사용했었습니다.
자바 7 이전 Iterator
// 자바 7 이전 Iterator
List<String> list = Arrays.asList("A", "B", "C", "D", "E");
Iterator<String> iterator = list.iterator();
while ((iterator.hasNext())) {
System.out.println(iterator.next());
}
자바 8 이후 Stream
- Iterator를 사용하는 것보다 훨씬 단순하고 간결하게 처리할 수 있습니다.
- Stream의 forEach는 함수형 인터페이스인 Consumer를 매개변수로 받고 있어 람다를 활용할 수 있습니다.
- Stream API는 매개변수로 함수형 인터페이스를 받고, 람다식은 반환 값으로 함수형 인터페이스를 반환합니다.
// 자바 8 Stream
List<String> list = Arrays.asList("A", "B", "C", "D", "E");
list.stream().forEach(System.out::println);
// Stream API
public interface Stream<T> extends BaseStream<T, java.util.stream.Stream<T>> {
void forEach(Consumer<? super T> action);
// (. . .) 생략
}
2. Stream의 특징
1. 람다식으로 요소 처리 코드를 제공합니다.
- Stream이 제공하는 요소 처리 메소드는 함수형 인터페이스 매개 타입을 가지기 때문에 람다식 또는 메소드 레퍼런스를 이용해서 구현할 수 있습니다.
public interface Stream<T> extends BaseStream<T, Stream<T>> {
Stream<T> filter(Predicate<? super T> predicate);
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
Stream<T> sorted(Comparator<? super T> comparator);
Stream<T> peek(Consumer<? super T> action);
void forEach(Consumer<? super T> action);
// (. . .) 생략
}
2. 내부 반복자를 사용하므로 병렬 처리가 쉽습니다.
[외부 반복자]
- 개발자가 코드로 직접 컬렉션의 요소를 반복해서 가져오는 코드 패턴
- Iterator는 요소를 가져오는 것부터 처리하는 것까지 모두 개발자가 작성해야합니다.
[내부 반복자]
- 컬렉션 내부에서 요소들을 반복시키고, 개발자는 요소당 처리해야 할 코드만 제공하는 코드 패턴
- 내부 반복자의 장점은 요소의 반복은 컬렉션에게 맡겨두고, 개발자는 요소 처리 코드에만 집중할 수 있습니다.
- Stream은 람다식으로 요소 처리 내용만 전달하면 되므로 코드가 간결해집니다.
- parallelStream을 이용해 병렬 처리를 쉽게 구현할 수 있습니다.
[병렬 처리]
- 한 가지 작업을 서브 작업으로 나누고, 서브 작업들을 분리된 스레드에서 병렬적으로 처리하는 것
- 여러 개의 스레드가 요소들을 부분적으로 합하고 이 부분합을 최종 결합해서 전체 합을 생성합니다.
- 병렬 처리는 스레드 풀 생성, 스레드 생성 등의 추가적인 비용이 발생하고 자료구조에 따라 성능이 달라질 수 있으므로 순차 처리보다 항상 실행 성능이 좋다고 판단할 수 없습니다.
- 아래의 실행 결과를 보면 병렬 처리는 여러 스레드를 활용하는 것을 확인할 수 있습니다.
List<String> list = Arrays.asList("A", "B", "C", "D", "E");
// 순차 처리
list.stream().forEach(l ->
System.out.println(l + " : " + Thread.currentThread().getName())
);
// 병럴 처리
list.parallelStream().forEach(l ->
System.out.println(l + " : " + Thread.currentThread().getName())
);
3. Stream은 중간 처리와 최종 처리를 할 수 있습니다.
- Stream은 요소에 대해 중간 처리와 최종 처리를 수행할 수 있습니다.
- 중간 처리(매핑, 필터링, 정렬 등)는 여러 번 사용할 수 있습니다.
- 최종 처리(반복, 집계처리 등)는 결과 처리이므로 한 번만 사용할 수 있습니다.
EX) List<People> 컬렉션에서 19세 이상의 사람이 몇 명인지 집계하세요.
List<People> peopleList = Arrays.asList(
new People("홍승길", 30),
new People("김진수", 5),
new People("이순미", 19),
new People("김영철", 21),
new People("박수진", 12)
);
// 19세 이상의 사람이 몇명인지 집계하세요.
long count = peopleList.stream()
.filter(p -> p.getAge() >= 19)
.count();
System.out.println(count); // 3
3. Stream의 종류
- 자바 8부터 새로 추가된 java.util.stream 패키지에는 여러 Stream API들이 포함되어 있습니다.
- BaseStream 인터페이스를 부모로 해서 실제로 사용하는 자식 인터페이스들이 상속 관계를 이루고 있습니다.
- Stream은 객체 요소를 처리하는 스트림이고, IntStream, LongStream, DoubleStream은 각각 기본 타입인 int, long, double 요소를 처리하는 스트림입니다.
Stream 구현 객체를 얻을 수 있는 메소드
파일로부터 스트림 얻기 예시
Path path = Paths.get("/Users/veneas/Desktop/dev/test.txt");
//Files.lines() 메소드 활용
Stream<String> stream1 = Files.lines(path, Charset.defaultCharset());
stream1.forEach(System.out::println);
//BufferedReader lines() 메소드 활용
File file = path.toFile();
FileReader fileReader = new FileReader(file);
BufferedReader bufferedReader = new BufferedReader(fileReader);
Stream<String> stream2 = bufferedReader.lines();
stream2.forEach(System.out::println);
4. Stream 파이프라인
- 대량의 데이터를 가공해서 축소하는 것을 리덕션이라 하는데, 데이터의 합계, 평균값, 카운팅, 최댓값, 최솟값 등이 대표적인 리덕션의 결과물이라고 볼 수 있습니다.
- 컬렉션의 요소를 리덕션의 결과물로 바로 집계할 수 없을 경우에는 중간 처리(필터링, 매핑, 정렬, 그루핑)를 이용하여 가공합니다.
- Stream은 데이터의 필터링, 매핑, 정렬, 그룹핑 등의 중간 처리와 합계, 평균, 카운팅, 최댓값, 최솟값 등의 최종 처리를 파이프라인으로 해결합니다.
- 파이프라인은 여러 개의 스트림이 연결되어있는 구조를 말합니다. (마치 컨베이어 벨트에서 분류되는 모습과도 비슷합니다.)
- 중간 스트림이 생성될 때 요소들이 바로 처리(Eager)되는 것이 아니라 최종 처리가 되기 전까지 중간 처리는 지연(Lazy)됩니다.
5. 중간 처리 메소드와 최종 처리 메소드
- Stream API의 대표적인 메소드입니다. 기본형 Stream 메소드는 생략했습니다.
'Backend > Java' 카테고리의 다른 글
[Java] 자바 Thread 생성하기 (0) | 2022.01.04 |
---|---|
[Java] 자바 8 Stream API 필터링 (filter, distinct) (0) | 2022.01.01 |
[Java] 자바 커스텀 예외 만들기(Custom Exception) (0) | 2021.12.28 |
[Java] 자바 예외 넘기기 (throws) (0) | 2021.12.27 |
[Java] 자바 try-with-resource (AutoCloseable) (0) | 2021.12.26 |