一、GroupBy的概念与组成
在 Java 中,Stream GroupBy 是一个用于将数据分组的功能。按照指定的元素进行分组,然后将操作应用到已分组的数据上。它由三个组成部分组成:分组的键、分组的值、以及将被应用到每个组的方程。
Stream GroupBy 提供了一个非常简单且灵活的方法来对复杂的数据集进行分组操作。通过这种方式,我们可以进行聚合、计数、筛选等各种操作。
List<Person> list = Arrays.asList(
new Person("John", "Boston", 21),
new Person("Sara", "Boston", 25),
new Person("Mark", "New York", 50),
new Person("Tim", "Boston", 32),
new Person("Tony", "New York", 45));
Map<String,List<Person>> cityToPersonListMap =
list.stream().collect(Collectors.groupingBy(Person::getCity));
在这个例子中,我们使用了Stream groupBy 来根据人所在的城市将人员分组。它返回一个由城市名称分组的人员列表。
二、GroupBy的优点和用途
Java Stream GroupBy 的功能非常强大,可以用于各种不同的用途。下面是一些常见的用例:
1、计数
Map<String, Long> countByCity = list.stream()
.collect(Collectors.groupingBy(Person::getCity, Collectors.counting()));
这个例子将按城市名称计算人数,并返回一个包含每个城市人数的 Map。
2、平均值
Map<String, Double> avgByCity = list.stream()
.collect(Collectors.groupingBy(Person::getCity, Collectors.averagingInt(Person::getAge)));
这段代码将计算在每个城市中每个人的平均年龄,并返回一个包含每个城市平均年龄的 Map。
3、分组键值连接和获取
Map<String, String> nameByCity = list.stream()
.collect(Collectors.groupingBy(Person::getCity,
Collectors.mapping(Person::getName, Collectors.joining(", "))));
这个例子将在每个城市中获取人名列表,并将他们按逗号分隔开来。
三、GroupBy的注意点与拓展
在使用 Java Stream GroupBy 时,有几个需要注意的点:
1、结果类型与返回值
在使用 Java Stream GroupBy 时,返回类型与方法的返回值有关。例如,我们可以通过调用Collectors.counting()方法来计数。
Map<String, Long> countByCity = list.stream()
.collect(Collectors.groupingBy(Person::getCity, Collectors.counting()));
同样的道理适用于其他的聚合操作。例如,我们可以使用 Collectors.summingInt 方法来将整数求和。
2、分组前进行筛选
Map<String, List<Person>> cityToPersonListMap = list.stream()
.filter(person -> person.getAge() >= 21)
.collect(Collectors.groupingBy(Person::getCity));
在这个例子中,我们使用 Stream 进行了一个筛选操作来筛选年龄大于等于 21 的人体。同样的道理适用于其他类型的筛选操作,例如,筛选出某个特定城市的人员。
3、多级分组
Map<String,Map<String,List<Person>>> stateToCityToPersonListMap =
list.stream().collect(Collectors.groupingBy(Person::getState,
groupingBy(Person::getCity)));
在这个例子中,我们使用 Stream GroupBy 进行了一个两级分组。首先按照国家名称分组,然后在每个国家的基础上按照城市名称分组。
4、修改分组键
Map<String, List<Person>> ageToPersons =
list.stream().collect(Collectors.groupingBy(person -> {
if (person.getAge() <= 25) {
return "young";
} else {
return "old";
}
}));
在这个例子中,我们从年龄键中获取了自定义键,从而创建了一个规则来将所有人分为两组:年轻和年老。
5、并行处理
Map<String, List<Person>> cityToPersonListMapParallel =
list.parallelStream().collect(Collectors.groupingBy(Person::getCity));
我们可以使用 java Stream 的 parallelStream() 方法来让代码并行运行。在这个方法中,分组操作可以并行运行,从而提高整个过程的速度。