Java Stream分组
外观
介绍[编辑 | 编辑源代码]
Java Stream分组是Java Stream API中的一个核心操作,允许开发者根据特定条件将流中的元素分类到不同的组中。通过Collectors.groupingBy()
方法,可以轻松实现按属性、条件或自定义逻辑对数据进行分组,这在数据处理和分析中非常有用。分组操作返回一个Map
,其中键是分组条件,值是对应的元素列表。
分组操作适用于以下场景:
- 按属性分类(如按员工部门分组)
- 按条件筛选(如按年龄范围分组)
- 多级分组(如先按国家再按城市分组)
基础分组[编辑 | 编辑源代码]
最简单的分组形式是使用Collectors.groupingBy()
按对象的某个属性分类。以下示例演示如何按字符串长度分组:
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class GroupingExample {
public static void main(String[] args) {
List<String> words = Arrays.asList("apple", "banana", "cherry", "date", "fig");
Map<Integer, List<String>> groupedByLength = words.stream()
.collect(Collectors.groupingBy(String::length));
System.out.println(groupedByLength);
}
}
输出:
{3=[fig], 4=[date], 5=[apple], 6=[banana, cherry]}
解释:
String::length
作为分类函数,生成分组的键(字符串长度)。- 结果是一个
Map
,键是长度,值是对应的单词列表。
多级分组[编辑 | 编辑源代码]
通过嵌套groupingBy()
可以实现多级分组。以下示例先按字符串长度分组,再按首字母分组:
Map<Integer, Map<Character, List<String>>> multiLevelGrouping = words.stream()
.collect(Collectors.groupingBy(
String::length,
Collectors.groupingBy(s -> s.charAt(0))
));
System.out.println(multiLevelGrouping);
输出:
{ 3={f=[fig]}, 4={d=[date]}, 5={a=[apple]}, 6={b=[banana], c=[cherry]} }
分组后操作[编辑 | 编辑源代码]
可以对分组后的结果进一步处理,例如计算每组的数量或求和:
计数分组[编辑 | 编辑源代码]
Map<Integer, Long> countByLength = words.stream()
.collect(Collectors.groupingBy(
String::length,
Collectors.counting()
));
System.out.println(countByLength);
输出:
{3=1, 4=1, 5=1, 6=2}
求和分组[编辑 | 编辑源代码]
假设有一个Product
类,按类别分组并计算价格总和:
class Product {
String category;
double price;
// 构造方法和getter省略
}
List<Product> products = Arrays.asList(
new Product("Electronics", 999.99),
new Product("Books", 19.99),
new Product("Electronics", 499.99)
);
Map<String, Double> sumByCategory = products.stream()
.collect(Collectors.groupingBy(
Product::getCategory,
Collectors.summingDouble(Product::getPrice)
));
System.out.println(sumByCategory);
输出:
{Electronics=1499.98, Books=19.99}
自定义分组逻辑[编辑 | 编辑源代码]
分组条件可以是任意Function
。以下示例按奇偶性分组数字:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Map<String, List<Integer>> oddEvenGroups = numbers.stream()
.collect(Collectors.groupingBy(
n -> n % 2 == 0 ? "Even" : "Odd")
);
System.out.println(oddEvenGroups);
输出:
{Odd=[1, 3, 5], Even=[2, 4]}
实际应用案例[编辑 | 编辑源代码]
案例1:订单按客户分组[编辑 | 编辑源代码]
class Order {
String customerId;
double amount;
// 构造方法和getter省略
}
List<Order> orders = Arrays.asList(
new Order("C101", 99.99),
new Order("C102", 149.99),
new Order("C101", 199.99)
);
Map<String, List<Order>> ordersByCustomer = orders.stream()
.collect(Collectors.groupingBy(Order::getCustomerId));
案例2:日志按级别分组[编辑 | 编辑源代码]
List<String> logs = Arrays.asList(
"ERROR: Disk full",
"INFO: User logged in",
"WARN: Connection timeout",
"ERROR: File not found"
);
Map<String, List<String>> logsByLevel = logs.stream()
.collect(Collectors.groupingBy(
log -> log.split(":")[0]
));
性能考虑[编辑 | 编辑源代码]
- 分组操作的时间复杂度通常为O(n),但多级分组会增加内存消耗。
- 对于大型数据集,可结合
parallelStream()
并行处理(需注意线程安全)。
总结[编辑 | 编辑源代码]
Java Stream分组通过Collectors.groupingBy()
提供强大的数据分类能力,支持:
- 单级与多级分组
- 分组后聚合操作(计数、求和等)
- 完全自定义的分组逻辑
以下流程图说明分组过程:
掌握此技术可显著提升集合数据处理的效率和代码可读性。