Java Stream 如何分组

你有没有过这种情况:手机相册里存了几百张照片,想找出所有“海边拍的”或者“2024年拍的”,翻找起来特别麻烦?要是能自动把相似的东西归到一块儿,找起来就方便多了。在Java编程里,有个叫Stream的工具,它就有“自动归拢”的本事,也就是我们常说的“分组”。

什么是Java Stream分组?

简单说,分组就是把一堆Java对象,按照某个共同的特征,分成好几组。比如你有一堆学生信息,要把同年级的放一块儿,或者把同一个省份的放一块儿,这就是分组。举个生活化的例子:把一堆水果按“种类”分组,苹果放一组,香蕉放一组,橙子放一组,这样找的时候直接找“苹果组”就行,不用翻所有水果。

Java Stream 如何分组

分组的核心方法:Collectors.groupingBy

Stream里做分组,主要靠Collectors.groupingBy这个方法,它就像个“分类整理员”,你告诉它“按什么特征分”,它就会自动把对象分到对应的组里。

举个实际的代码例子吧,假设我们有一堆员工对象,每个员工有“姓名”“部门”“工资”这几个属性:

`java

class Employee {

String name;

String department;

double salary;

// 构造方法、getter省略

}

`

如果想把员工按“部门”分组,也就是把“市场部”的员工放一组,“技术部”的放另一组,代码就这么写:

`java

List<Employee> employees = ......; // 假设这里已经有员工列表

Map<String, List<Employee>> employeesByDept = employees.stream()

.collect(Collectors.groupingBy(Employee::getDepartment));

`

是不是很好懂?Employee::getDepartment就是告诉分类员,“按员工的部门特征分”,最后得到的Map里,键是部门名称(比如“技术部”),值就是这个部门的所有员工列表。

进阶用法:分组后再统计

有时候分组不止是“归拢”,还要知道每组有多少个,或者每组的平均工资是多少。比如刚才的员工例子,除了按部门分组,还想知道每个部门有多少人,这时候可以给groupingBy加个“后续处理”,让分类员帮我们统计:

`java

Map<String, Long> countByDept = employees.stream()

.collect(Collectors.groupingBy(

Employee::getDepartment, // 按部门分组

Collectors.counting() // 每组统计数量

));

`

这样得到的Map里,键是部门,值是这个部门的员工数,比如“技术部:5人”“市场部:3人”。再比如想知道每个部门的平均工资,把counting换成summingDouble就行:

`java

Map<String, Double> avgSalaryByDept = employees.stream()

.collect(Collectors.groupingBy(

Employee::getDepartment,

Collectors.averagingDouble(Employee::getSalary)

));

`

这就像你把水果按种类分好后,还顺便数了每类水果有几个,或者称了每类的总重量,不用再单独去算。

注意的小细节

分组的时候,要注意“特征不能重复”。比如如果按“姓名”分组,要是有两个同名的员工,那他们会被分到同一个组里,这可能不是你想要的结果。所以选分组特征的时候,最好选能唯一区分组的,比如部门、省份这种,而不是姓名这种可能重复的。

总的来说,Java Stream的分组就像你整理家里的杂物,按“类型”“用途”分好类,找起来省心不少。不管是统计数量、计算平均值,还是按自定义的特征分组,只要用好Collectors.groupingBy,就能让代码变得简洁又好懂,不用自己写一堆循环去判断分组了。

上一篇 Java 如何创建对象