자바 :: 3.자바 스트림API 최종연산
최종 연산 메서드
대표적인 유형과 메서드는 다음과 같습니다. 대부분의 최종연산은 결과값만 리턴되므로 별도의 출력문을 연결해 사용하기 어렵습니다. 각 메서드 설명에 사용된 예제에서는 주석으로 결과를 표기 했으며 일부 가능한 경우만 직접 출력하고 있습니다.
- 요소의 출력 : forEach()
- 요소의 소모 : reduce()
- 요소의 검색 : findFirst(), findAny()
- 요소의 검사 : anyMatch(), allMatch(), noneMatch()
- 요소의 통계 : count(), min(), max()
- 요소의 연산 : sum(), average()
- 요소의 수집 : collect()
1) forEach()
스트림의 요소들을 순환 하면서 반복해서 처리해야 하는 경우 사용 합니다.
intList.stream().forEach(System.out::println); // 1,2,3
intList.stream().forEach(x -> System.out.printf("%d : %d\n",x,x*x)); // 1,4,9
2) reduce()
map 과 비슷하게 동작하지만 개별연산이 아니라 누적연산이 이루어진다는 차이가 있습니다.
두개의 인자 즉 n, n+1 을 가지며 연산결과는 n 이 되고 다시 다음 요소와 연산을 하게 됩니다. 즉 1,2 번째 요소를 연산하고 그 결과와 3번째 요소를 연산하는 식입니다.
int sum = intList.stream().reduce((a,b) -> a+b).get();
System.out.println("sum: "+sum); // 6
3) findFirst(), findAny()
두 메서드는 스트림에서 지정한 첫번째 요소를 찾는 메서드 입니다.
보통 filter() 와 함께 사용되고 findAny() 는 parallelStream() 에서 병렬 처리시 가장 먼저 발견된 요소를 찾는 메서드로 결과는 스트림 원소의 정렬 순서와 상관 없습니다.
strList.stream().filter(s -> s.startsWith("H")).findFirst().ifPresent(System.out::println); //Hwang
strList.parallelStream().filter(s -> s.startsWith("H")).findAny().ifPresent(System.out::println); //Hwang or Hong
- findAny() 를 parralelStream() 과 함께 사용하는 경우 일반적으로 findFirst() 와 결과가 같다.(보장되는 것은 아님)
- parallelStream() 과 사용한 경우 실제 스트림 순서와는 다르게 선택될 수 있음.
- findFirst() 와 findAny() 의 리턴값은 Optional 이므로 ifPresent() 를 이용해 출력.
4) anyMatch(), allMatch(), noneMatch()
스트림의 요소중 특정 조건을 만족하는 요소를 검사하는 메서드
원소중 일부, 전체 혹은 일치하는 것이 없는 경우를 검사하고 boolean 값을 리턴합니다. noneMatch()의 경우 일치하는 것이 하나도 없을때 true.
boolean result1 = strList.stream().anyMatch(s -> s.startsWith("H")); //true
boolean result2 = strList.stream().allMatch(s -> s.startsWith("H")); //false
boolean result3 = strList.stream().noneMatch(s -> s.startsWith("T")); //true
System.out.printf("%b, %b, %b",result1,result2, result3);
5) count(), min(), max()
스트림의 원소들로 부터 전체 개수, 최소값, 최대값을 구하기 위한 메서드 입니다.
min(), max() 의 경우 Comparator 를 인자로 요구 하고 있으므로 기본 Comparator 들을 사용하거나 직접 람다 표현식으로 구현해야 합니다.
intList.stream().count(); // 3
intList.stream().filter(n -> n !=2 ).count(); // 2
intList.stream().min(Integer::compare).ifPresent(System.out::println);; // 1
intList.stream().max(Integer::compareUnsigned).ifPresent(System.out::println);; // 3
strList.stream().count(); // 3
strList.stream().min(String::compareToIgnoreCase).ifPresent(System.out::println); // Hong
strList.stream().max(String::compareTo).ifPresent(System.out::println); // Kang
6) sum(), average()
스트림 원소들의 합계를 구하거나 평균을 구하는 메서드 입니다.
reduce() 와 map() 을 이용해도 구현이 가능 합니다. 이경우 리턴값이 옵셔널이기 때문에 ifPresent()를 이용해 값을 출력할 수 있습니다.
intList.stream().mapToInt(Integer::intValue).sum(); // 6
intList.stream().reduce((a,b) -> a+b).ifPresent(System.out::println); // 6
intList.stream().mapToInt(Integer::intValue).average(); // 2
intList.stream().reduce((a,b) -> a+b).map(n -> n/intList.size()).ifPresent(System.out::println); // 2
7) collect()
스트림의 결과를 모으기 위한 메서드로 Collectors 객체에 구현된 방법에 따라 처리하는 메서드 입니다.
최종 처리후 데이터를 변환하는 경우가 많기 때문에 잘 알아 두어야 합니다. 용도별로 사용할 수 있는 Collectors 의 메서드는 기능별로 다음과 같습니다.
- 스트림을 배열이나 컬렉션으로 변환 : toArray(), toCollection(), toList(), toSet(), toMap()
- 요소의 통계와 연산 메소드와 같은 동작을 수행 : counting(), maxBy(), minBy(), summingInt(), averagingInt() 등
- 요소의 소모와 같은 동작을 수행 : reducing(), joining()
- 요소의 그룹화와 분할 : groupingBy(), partitioningBy()
strList.stream().map(String::toUpperCase).collect(Collectors.joining("/")); // Hwang/Hong/Kang
strList.stream().collect(Collectors.toMap(k -> k, v -> v.length())); // {Hong=4, Hwang=5, Kang=4}
intList.stream().collect(Collectors.counting());
intList.stream().collect(Collectors.maxBy(Integer::compare));
intList.stream().collect(Collectors.reducing((a,b) -> a+b)); // 6
intList.stream().collect(Collectors.summarizingInt(x -> x)); //IntSummaryStatistics{count=3, sum=6, min=1, average=2.000000, max=3}
Map<Boolean, List<String>> group = strList.stream().collect(Collectors.groupingBy(s -> s.startsWith("H")));
group.get(true).forEach(System.out::println); // Hwang, Hong
Map<Boolean, List<String>> partition = strList.stream().collect(Collectors.partitioningBy(s -> s.startsWith("H")));
partition.get(true).stream().forEach(System.out::println); // Hwang, Hong
- toMap() 을 사용해서 문자열 스트림의 값을 키로 하고 문자열의 길이를 값으로 하는 맵으로 변환.
- counting, maxBy, reducing 은 각각 count(), max(), reduce() 메서드와 동일한 결과.
- summarizingInt 는 IntSummaryStatistics 를 리턴하며 count, sum, min, average, max 값을 참조할 수 있음.
- groupingBy는 특정 조건에 따라 데이터를 구분해서 저장.
- partitioningBy는 특정 조건으로 데이터를 두그룹으로 나누어 저장.