1. Stream
- 집계연산을 지원하는 일련의 데이터 소스 객체입니다.
- 데이터를 저장하는 용도가 아닌 계산하는 용도로 사용됩니다.
- 데이터의 변환과 계산을 위한 중간 연산과 최종 연산을 제공합니다.
- 컬렉션과 다르게 내부적으로 연산이 수행됩니다.
- 병렬화하여 다중 코어 아키텍처를 활용하는데 유용합니다.
2. 선언형 프로그래밍과 Stream
- Stream 객체를 사용하여 데이터 처리를 섬세하게 표현할 수 있습니다.
- 데이터 처리 패턴이 선언적인 연산인 SQL과 유사합니다.
- 함수형 프로그래밍과 선언형 연산을 지원하여 구현을 감추고 기능을 명시적으로 표현할 수 있습니다.
3. 파이프라인 및 연산 체이닝
- Stream은 더 큰 파이프라인 체이닝을 형성하기 위해 자기 자신을 리턴합니다.
- 연산의 효율성을 위한 게으른 연산을 수행하며, 최종 연산시에만 결과 데이터가 응답됩니다.
- 집계연산의 연결은 마치 데이터에 대한 쿼리를 작성하는 것과 같습니다.
4. 병렬 처리 및 효율성
List<Integer> transactionsIds =
transactions.parallelStream()
.filter(t -> t.getType() == Transaction.GROCERY)
.sorted(comparing(Transaction::getValue).reversed())
.map(Transaction::getId)
.collect(toList());
- 특별한 코드를 작성하지 않고 데이터를 병렬로 처리하는 기능을 제공합니다.
- 특히 대용량 데이터를 효과적으로 처리할 수 있습니다.
5. Stream 연산
중간연산
- 반환형은 Stream이며, 서로 연결하여 파이프라인을 형성하는 것이 목적입니다.
- 중간 연산은 게으르게 수행됩니다.
- 스트림 파이프라인에 종단 연산이 호출될 때까지 중간연산은 어떤 처리도 수행되지 않습니다.
- 이를 통해 단일 순회가 가능하므로 효율성이 크게 향상됩니다.
Filtering
- filter(Predicate), distinct, limit, skip
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
List<Integer> twoEvenSquares =
numbers.stream()
.filter(n -> {
System.out.println("filtering " + n);
return n % 2 == 0;
})
.limit(2)
.collect(toList());
Mapping
- map
List<Integer> transactionIds =
transactions.stream()
.map(Transaction::getId)
.collect(toList());
최종연산
- Stream 파이프라인을 종료하며 결과를 생성합니다.
Finding and Matching
boolean expensive =
transactions.stream()
.allMatch(t -> t.getValue() > 100);
- anyMatch, allMatch, noneMatch, findAny, findFirst
Reducing
int product = numbers.stream().reduce(1, (a, b) -> a * b);
int product = numbers.stream().reduce(1, Integer::max);
- reduce 연산은 스트림의 모든 요소를 반복적으로 조합하여 결과를 생성합니다.
- 초기값과 연산자 두 개의 매개변수를 사용하여 스트림의 모든 요소를 조합합니다.
Collect
- Stream의 요소를 수집하는데 사용됩니다.
- 다양한 결과 형태로 Stream을 변환할 때 사용됩니다.
- Collectors 클래스에서 수집 연산을 지원하는 다양한 정적 메소드를 제공합니다.
수집하기
stream.collect(Collectors.toList());
stream.collect(Collectors.toSet());
stream.collect(Collectors.toMap(
Function.identity(), // 키로 사용될 함수
String::length // 값으로 사용될 함수
));
연산
stream.collect(Collectors.joining(", "));
stream.collect(Collectors.averagingInt(Integer::intValue));
stream.collect(Collectors.groupingBy(String::length));
6. Numeric Streams
- 박싱 작업의 오버헤드를 줄이기 위해 도입되었습니다.
- IntStream, DoubleStream, LongStream 등이 있습니다.
- 기본 데이터 타입에 특화된 연산을 제공하여 성능을 개선합니다. (sum, average, rangeClosed 등)
int statementSum =
transactions.stream()
.mapToInt(Transaction::getValue)
.sum(); // works!
IntStream oddNumbers =
IntStream.rangeClosed(10, 30)
.filter(n -> n % 2 == 1);
7. Stream 생성 방법
- 컬렉션, 배열, 값, 파일, 함수 등 다양한 방법으로 생성할 수 있습니다.
Stream<Integer> numbersFromValues = Stream.of(1, 2, 3, 4);
int[] numbers = {1, 2, 3, 4};
IntStream numbersFromArray = Arrays.stream(numbers);
long numberOfLines =
Files.lines(Paths.get(“yourFile.txt”), Charset.defaultCharset())
.count();
유한스트림
- 명확한 시작과 끝이 있는 스트림을 의미합니다.
- 대부분의 스트림 소스에서 생성되는 스트림은 유한 스트림입니다.
무한스트림
- 시작은 있지만 끝은 없는 스트림을 의미합니다.
- Stream.iterate 또는 Stream.generate 메서드를 사용하여 생성됩니다.
- 크기를 제한하기 위해 limit 메서드를 사용해야 합니다.
Stream<Integer> infiniteStream1 = Stream.iterate(0, n -> n + 1);
infiniteStream1.limit(5).forEach(System.out::println); // 0, 1, 2, 3, 4를 출력합니다.
출처
'Java' 카테고리의 다른 글
[Java의 정석] 13-2. 스레드: 우선순위, 그룹, 데몬 스레드 (2) | 2023.11.27 |
---|---|
[Java의 정석] 13-1. 스레드: 프로세스와 스레드 (0) | 2023.11.27 |
[Java][Tutorial] 3-3. Collections: Aggregate Operations (0) | 2023.10.20 |
[Java][Tutorial] 3-2. Collections: Queue, Deque, Map (0) | 2023.10.15 |
[Java][Tutorial] 3-1. Collections: Collection, Set, List (2) | 2023.10.15 |