Java 8 groupingBy Collector 예제
123123
1. 소개
이 기사에서는 다양한 예제를 사용하여 groupingBy 콜렉터가 작동 하는 방식을 살펴 본다 .
이 기사에서 다루는 내용을 이해하려면 Java 8 기능에 대한 기본 지식이 필요합니다. Java 8 Streams 소개 및 Java 8 Collectors 안내서를 살펴볼 수 있습니다 .
2. GroupingBy Collectors
Java 8 Stream API를 사용하면 선언적인 방식으로 데이터 모음을 처리 할 수 있습니다.
정적 팩토리 메소드 인 Collectors.groupingBy () 및 Collectors.groupingByConcurrent () 는 SQL 언어 의 ' GROUP BY' 절 과 유사한 기능을 제공 합니다. 속성을 기준으로 객체를 그룹화하고 결과를 Map 인스턴스 에 저장하는 데 사용됩니다 .
오버로드 된 groupingBy 메소드 :
- 메소드 매개 변수로 분류 기능 사용 :
static <T,K> Collector<T,?,Map<K,List<T>>>
groupingBy(Function<? super T,? extends K> classifier)
- 메소드 매개 변수로 분류 함수 및 두 번째 콜렉터 사용 :
static <T,K,A,D> Collector<T,?,Map<K,D>>
groupingBy(Function<? super T,? extends K> classifier,
Collector<? super T,A,D> downstream)
- 분류 함수, 공급 업체 메소드 ( 최종 결과를 포함 할 Map 구현 제공 ) 및 메소드 매개 변수로 두 번째 콜렉터를 사용하십시오.
static <T,K,D,A,M extends Map<K,D>> Collector<T,?,M>
groupingBy(Function<? super T,? extends K> classifier,
Supplier<M> mapFactory, Collector<? super T,A,D> downstream)
2.1. 코드 설정 예
groupingBy ()의 사용법을 보여주기 위해 BlogPost 클래스를 정의 해 봅시다 ( 블로그 포스트 객체 스트림을 사용할 것입니다 ).
class BlogPost {
String title;
String author;
BlogPostType type;
int likes;
}
BlogPostType :
enum BlogPostType {
NEWS,
REVIEW,
GUIDE
}
목록 의 블로그 게시물의 객체 :
List<BlogPost> posts = Arrays.asList( ... );
유형 과 작성자 속성 의 조합으로 게시물을 그룹화하는 데 사용될 Tuple 클래스 도 정의 해 보겠습니다 .
class Tuple {
BlogPostType type;
String author;
}
2.2. 단일 열로 간단한 그룹화
분류 함수를 매개 변수로만 사용하는 가장 간단한 groupingBy 메서드 부터 시작하겠습니다 . 분류 함수는 스트림의 각 요소에 적용됩니다. 함수가 반환 한 값은 groupingBy 콜렉터 에서 가져 오는 맵의 키로 사용됩니다 .
블로그 게시물 목록에서 블로그 게시물을 유형별로 그룹화하려면 다음을 수행하십시오.
Map<BlogPostType, List<BlogPost>> postsPerType = posts.stream()
.collect(groupingBy(BlogPost::getType));
2.3. 복잡한 맵 키 유형으로 그룹화
분류 함수는 스칼라 또는 문자열 값만 리턴하도록 제한되지 않습니다. 필요한 equals 및 hashcode 메소드를 구현하는 한 결과 맵의 키는 모든 오브젝트가 될 수 있습니다 .
Tuple 인스턴스 에서 결합 된 유형 및 작성자 별로 목록의 블로그 게시물을 기준으로 그룹화하려면 다음을 수행하십시오 .
Map<Tuple, List<BlogPost>> postsPerTypeAndAuthor = posts.stream()
.collect(groupingBy(post -> new Tuple(post.getType(), post.getAuthor())));
2.4. 리턴 된 맵 값 유형 수정
groupingBy 의 두 번째 과부하 는 추가 두 번째 수집기 (다운 스트림 수집기)를 가져와 첫 번째 수집기의 결과에 적용됩니다.
다운 스트림 콜렉터가 아닌 분류 함수 만 지정하면 toList () 콜렉터가 뒤에서 사용됩니다.
하자가 사용 toSet () 다운 스트림 콜렉터로 수집을하고 얻을 설정 블로그 게시물을 (대신의 목록 ) :
Map<BlogPostType, Set<BlogPost>> postsPerType = posts.stream()
.collect(groupingBy(BlogPost::getType, toSet()));
2.5. 여러 필드로 그룹화
다운 스트림 콜렉터의 다른 적용은 첫 번째 그룹의 결과를 기준으로 2 차 그룹화를 수행하는 것입니다.
먼저 BlogPost 목록 을 작성자 별로 그룹화 한 다음 유형별로 그룹화하려면 다음을 수행하십시오 .
Map<String, Map<BlogPostType, List>> map = posts.stream()
.collect(groupingBy(BlogPost::getAuthor, groupingBy(BlogPost::getType)));
2.6. 그룹화 된 결과에서 평균 얻기
다운 스트림 콜렉터를 사용하여 분류 함수의 결과에 집계 함수를 적용 할 수 있습니다.
각 블로그 게시물 유형에 대한 평균 좋아요 수를 찾으려면 다음을 수행하십시오 .
Map<BlogPostType, Double> averageLikesPerType = posts.stream()
.collect(groupingBy(BlogPost::getType, averagingInt(BlogPost::getLikes)));
2.7. 그룹화 된 결과에서 합계 얻기
각 유형 의 좋아요 총합을 계산하려면 다음을 수행하십시오 .
Map<BlogPostType, Integer> likesPerType = posts.stream()
.collect(groupingBy(BlogPost::getType, summingInt(BlogPost::getLikes)));
2.8. 그룹화 된 결과에서 최대 또는 최소 얻기
우리가 수행 할 수있는 또 다른 집계는 최대 수의 좋아요를 가진 블로그 게시물을 얻는 것입니다.
Map<BlogPostType, Optional<BlogPost>> maxLikesPerPostType = posts.stream()
.collect(groupingBy(BlogPost::getType,
maxBy(comparingInt(BlogPost::getLikes))));
마찬가지로 minBy 다운 스트림 콜렉터를 적용 하여 최소한의 좋아요 수로 블로그 게시물을 가져올 수 있습니다.
있습니다 maxBy 및 minBy 수집 계정으로이 적용되는 컬렉션이 비어있을 수있는 가능성을. 이것이 맵의 값 유형이 Optional
2.9. 그룹화 된 결과의 속성에 대한 요약 얻기
수집기 API 제공 우리가 같은 시간에 수, 합계, 최소, 최대 및 숫자 속성의 평균을 계산해야 할 때 경우에 사용할 수있는 요약하는 수집기.
각기 다른 유형에 대한 블로그 게시물의 likes 속성에 대한 요약을 계산해 보겠습니다.
Map<BlogPostType, IntSummaryStatistics> likeStatisticsPerType = posts.stream()
.collect(groupingBy(BlogPost::getType,
summarizingInt(BlogPost::getLikes)));
각 유형 의 IntSummaryStatistics 객체에는 likes 속성 의 개수, 합계, 평균, 최소 및 최대 값이 포함됩니다 . double 및 long 값에 대한 추가 요약 개체가 있습니다.
2.10. 그룹화 된 결과를 다른 유형으로 맵핑
분류 기능의 결과에 매핑 다운 스트림 콜렉터를 적용하여 더 복잡한 집계를 수행 할 수 있습니다 .
각 블로그 게시물 유형 에 대한 게시물 제목을 연결해 보겠습니다 .
Map<BlogPostType, String> postsPerType = posts.stream()
.collect(groupingBy(BlogPost::getType,
mapping(BlogPost::getTitle, joining(", ", "Post titles: [", "]"))));
여기서 우리가 한 일은 각 BlogPost 인스턴스를 제목 에 매핑 한 다음 게시물 제목 스트림을 연결된 String으로 줄이는 것 입니다. 이 예제에서 맵 값 의 유형은 기본 목록 유형 과도 다릅니다 .
2.11. 맵타입 그룹핑 반환
groupingBy 콜렉터를 사용하는 경우 리턴 된 Map 유형에 대해 가정 할 수 없습니다 . 우리의 유형에 대해 구체적으로하려면 지도 우리가 다음 우리는의 제 3 변형 사용하여 그룹에서 싶어 groupingBy의 우리의 유형을 변경할 수있는 방법 지도를 통과하여 지도 공급 기능을.
하자가 검색 EnumMap는을 는 전달하여 EnumMap는의 받는 공급 기능을 groupingBy의 방법 :
EnumMap<BlogPostType, List<BlogPost>> postsPerType = posts.stream()
.collect(groupingBy(BlogPost::getType,
() -> new EnumMap<>(BlogPostType.class), toList()));
3. 동시성 Grouping by Collector
groupingBy 와 유사하게 멀티 코어 아키텍처를 활용 하는 groupingByConcurrent 콜렉터가 있습니다. 이 콜렉터에는 groupingBy 콜렉터 의 각각의 오버로드 된 메소드와 정확히 동일한 인수를 취하는 3 개의 오버로드 된 메소드가 있습니다 . 그러나 groupingByConcurrent 콜렉터 의 리턴 유형은 ConcurrentHashMap 클래스 의 인스턴스 또는 그 서브 클래스 여야 합니다.
그룹화 작업을 동시에 수행하려면 스트림이 병렬이어야합니다.
ConcurrentMap<BlogPostType, List<BlogPost>> postsPerType = posts.parallelStream()
.collect(groupingByConcurrent(BlogPost::getType));
Map 공급자 함수를 groupingByConcurrent 콜렉터 에 전달하기로 선택한 경우 함수가 ConcurrentHashMap 또는 서브 클래스를 리턴하는지 확인해야 합니다.
4. Java 9 추가
Java 9는 groupingBy 와 함께 작동하는 두 개의 새로운 수집기를 가져 왔습니다. 이에 대한 자세한 정보는 여기를 참조하십시오 .
5. 결론
이 기사에서는 Java 8 Collectors API 에서 제공 하는 groupingBy 콜렉터 사용법에 대한 몇 가지 예를 보았습니다 .
groupingBy 를 사용하여 속성 중 하나를 기반으로 요소 스트림을 분류하는 방법과 분류 결과를 추가로 수집, 변경 및 최종 컨테이너로 줄일 수있는 방법을 살펴 보았습니다 .
이 기사에 대한 예제의 완전한 구현은 GitHub 프로젝트 에서 찾을 수 있습니다 .
참고
'Java' 카테고리의 다른 글
Keycloak의 로그인 페이지 사용자 정의 (0) | 2021.09.20 |
---|---|
Java 8 Stream 불변 Collection (0) | 2020.06.27 |
Java 8 Collectors 베스트 예제 (0) | 2020.06.24 |
Java 8 Functional Interfaces (0) | 2020.06.22 |
Java 8 Stream findFirst findAny 차이 (0) | 2020.06.21 |