To Dare Is To Do!
Stream 본문
Stream이란?
Java 8부터 추가된 기술로 람다를 활용해 배열과 컬렉션을 함수형으로 간단하게 처리할 수 있는 기술이다.
특징
- 람다식으로 요소 처리 코드를 제공한다.
람다식을 사용함으로써 간결하고 명확한 문법으로 코드의 가독성을 높인다.
List<String> names = Arrays.asList("Tom", "Jerry", "Spike");
names.stream()
.filter(name -> name.startsWith("T"))
.forEach(System.out::println); // Tom
filter(name -> name.startsWith("T")): 람다식을 사용하여 이름이 "T"로 시작하는 요소를 필터링한다. forEach(System.out::println): 람다식을 사용하여 필터링된 요소를 출력합니다.
- 원본 데이터를 변경하지 않는다.
Stream API는 불변성을 유지하며 원본 데이터를 변경하지 않는다.
대신, 원본 데이터를 기반으로 새로운 스트림을 생성하고 처리하여 데이터를 안전하게 다룰 수 있게 해준다.
List<String> names = Arrays.asList("Tom", "Jerry", "Spike");
List<String> filteredNames = names.stream()
.filter(name -> name.startsWith("T"))
.collect(Collectors.toList());
System.out.println(names); // [Tom, Jerry, Spike]
System.out.println(filteredNames); // [Tom]
원본 리스트 names는 변경되지 않고, 필터링된 새로운 리스트 filteredNames가 생성된다.
- 내부 반복자를 사용하므로 병렬 처리가 쉽다.
Stream API는 내부 반복자를 사용하여 요소를 처리한다. 이는 병렬 처리를 쉽게 구현할 수 있도록 한다.
내부 반복자는 데이터의 순회와 처리를 스트림이 관리하기 때문에, 개발자는 병렬 처리의 복잡성을 신경 쓰지 않아도 된다.
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
int sum = numbers.parallelStream()
.filter(n -> n % 2 == 0)
.reduce(0, Integer::sum);
System.out.println(sum); // 30 (2 + 4 + 6 + 8 + 10)
parallelStream()을 사용하여 병렬 스트림을 생성하고, 짝수만 필터링하여 합계를 구한다.
내부적으로 병렬 처리가 수행되므로 성능 향상 가능
+외부 반복과 내부 반복
외부 반복 : 개발자가 코드로 직접 컬렉션의 요소를 반복해서 가져오는 패턴의 코드를 말한다.
ex) for문, Iterator를 사용하는 while문 등
내부 반복 : 컬렉션 내부에서 요소들을 반복시키고 개발자는 요소당 처리해야 할 코드만 제공하는 패턴의 코드를 말한다.
- 연산 처리 과정이 중간 연산(과정)과 최종 연산(과정)으로 나뉜다.
스트림은 데이터의 필터링, 매핑, 정렬, 그룹핑 등의 중간 연산과 합계, 카운팅, 최대 / 최소 값 등의 최종 연산을 파이프라인으로 해결함
파이프라인은 여러 개의 스트림이 연결되어 있는 구조를 의미하며 최종 처리를 제외하고는 모두 중간 처리 스트림이다.
Stream 중간 연산
- 스트림을 반환하며, 연속적인 처리가 가능하다.
- 지연 연산(Lazy Evaluation)을 통해 최종 연산이 호출될 때까지 실제로 실행되지 않는다.
filter(Predicate) : 주어진 Predicate를 만족하는 요소들로 구성된 스트림을 반환
Stream<T> filteredStream = stream.filter(element -> element > 10);
distinct() : 중복된 요소를 제거한 스트림을 반환
Stream<T> distinctStream = stream.distinct();
limit(n) : 주어진 수만큼의 요소를 포함하는 스트림을 반환
Stream<T> limitedStream = stream.limit(5);
skip(n) : 처음 n개의 요소를 건너뛴 나머지 요소들로 구성된 스트림을 반환
Stream<T> skippedStream = stream.skip(3);
map(Function) : 각 요소에 함수를 적용하여 새로운 요소들로 구성된 스트림을 반환
Stream<R> mappedStream = stream.map(element -> element.toString());
flatMap() : 각 요소에 함수를 적용하여 생성된 스트림들을 하나의 스트림으로 평면화(flattening)하여 반환
Stream<R> flatMappedStream = stream.flatMap(element -> Stream.of(element.split(" ")));
Stream 최종 연산
- 스트림을 소모하며, 결과를 반환하거나 부작용을 일으킨다.
- 최종 연산이 호출되면 스트림의 요소가 실제로 처리한다.
(boolean) allMatch(Predicate) : 모든 스트림 요소가 Predicate와 일치하는지 검사하여 boolean 값을 반환
boolean allMatch = stream.allMatch(element -> element > 10);
(boolean) anyMatch(Predicate) : 하나라도 일치하는 요소가 있는지 검사하여 boolean 값을 반환
boolean anyMatch = stream.anyMatch(element -> element > 10);
(boolean) noneMatch(Predicate) : 매치되는 요소가 없는지 검사하여 boolean 값을 반환
boolean noneMatch = stream.noneMatch(element -> element > 10);
(Optional) findAny() : 현재 스트림에서 임의의 요소 반환, 요소가 없으면 Optional.empty를 반환
Optional<T> anyElement = stream.findAny();
(Optional) findFirst() : 스트림의 첫번째 요소 반환, 요소가 없으면 Optional.empty를 반환
Optional<T> firstElement = stream.findFirst();
reduce() : 모든 스트림 요소를 처리해 값을 도출. 두 개의 인자를 가짐
Optional<T> reduced = stream.reduce((a, b) -> a + b);
collect() : 스트림을 reduce하여 list, map, 정수 형식 컬렉션을 만
List<T> list = stream.collect(Collectors.toList());
(void) forEach() : 스트림 각 요소를 소비하며 람다 적용
stream.forEach(element -> System.out.println(element));
(Long) count : 스트림 요소 개수 반환
long count = stream.count();
'Java' 카테고리의 다른 글
자바 면접 스터디(1) (0) | 2024.10.04 |
---|---|
java 면접 질문 공부 (1) | 2024.09.02 |
thread pool (3) | 2024.08.06 |
hashcode(), equals() (0) | 2024.08.04 |
StringBuffer, StringBuilder, string (0) | 2024.08.04 |