这篇文章展示了如何使用Streams API中可用的Collectors
将具有groupingBy
的流元素和具有partitioningBy
的流元素进行groupingBy
。
考虑一系列Employee
对象,每个对象都有名称,城市和销售数量,如下表所示:
+----------+------------+-----------------+
| Name | City | Number of Sales |
+----------+------------+-----------------+
| Alice | London | 200 |
| Bob | London | 150 |
| Charles | New York | 160 |
| Dorothy | Hong Kong | 190 |
+----------+------------+-----------------+
分组
让我们开始使用命令式(Java-Lamba)按城市对员工进行分组:
Map<String, List<Employee>> result = new HashMap<>();
for (Employee e : employees) {String city = e.getCity();List<Employee> empsInCity = result.get(city);if (empsInCity == null) {empsInCity = new ArrayList<>();result.put(city, empsInCity);}empsInCity.add(e);
}
您可能熟悉这样的代码编写,并且您可以看到,完成如此简单的任务需要很多代码!
在Java 8中,您可以使用groupingBy
收集器对单个语句执行相同的操作,如下所示:
Map<String, List<Employee>> employeesByCity =employees.stream().collect(groupingBy(Employee::getCity));
结果如下图:
{New York=[Charles], Hong Kong=[Dorothy], London=[Alice, Bob]}
通过将counting
收集器传递给groupingBy
收集器,还可以计算每个城市的雇员counting
。 第二收集器对分类到同一组的流中的所有元素执行进一步的还原操作。
Map<String, Long> numEmployeesByCity =employees.stream().collect(groupingBy(Employee::getCity, counting()));
结果如下图:
{New York=1, Hong Kong=1, London=2}
顺便说一句,这等效于以下SQL语句:
select city, count(*) from Employee group by city
另一个示例是计算每个城市的平均销售数量,可以使用averagingInt
收集器结合groupingBy
收集器来完成:
Map<String, Double> avgSalesByCity =employees.stream().collect(groupingBy(Employee::getCity,averagingInt(Employee::getNumSales)));
结果如下图:
{New York=160.0, Hong Kong=190.0, London=175.0}
分区
分区是一种特殊的分组,其中的结果映射最多包含两个不同的组-一个用于true
,一个用于false
。 例如,如果您想找出最好的员工是谁,则可以使用partitioningBy
收集器将他们划分为销售额大于N的员工和不属于N的员工。
Map<Boolean, List<Employee>> partitioned =employees.stream().collect(partitioningBy(e -> e.getNumSales() > 150));
这将产生以下结果:
{false=[Bob], true=[Alice, Charles, Dorothy]}
您还可以通过将groupingBy
收集器传递给partitioningBy
收集器来组合分区和分组。 例如,您可以计算每个分区内每个城市的雇员人数:
Map<Boolean, Map<String, Long>> result =employees.stream().collect(partitioningBy(e -> e.getNumSales() > 150,groupingBy(Employee::getCity, counting())));
这将产生一个两层的Map:
{false={London=1}, true={New York=1, Hong Kong=1, London=1}}
翻译自: https://www.javacodegeeks.com/2015/11/java-8-streams-api-grouping-partitioning-stream.html