Java Stream API实战:高效集合操作与性能优化
一、Stream API核心概念
Java 8引入的Stream API彻底改变了集合处理方式,它提供了一种声明式、函数式的数据处理方法。与传统的for循环相比,Stream API具有以下优势:
- 代码更简洁、可读性更强
- 支持并行处理提升性能
- 内置丰富的中间操作和终端操作
- 延迟执行特性优化资源使用
二、Stream操作分类与实战
Stream操作分为中间操作(Intermediate Operations)和终端操作(Terminal Operations):
1. 中间操作示例
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// 过滤和映射
List<String> result = names.stream()
.filter(name -> name.length() > 3)
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(result); // 输出: [ALICE, CHARLIE, DAVID]
2. 终端操作示例
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
// 聚合操作
int sum = numbers.stream()
.reduce(0, Integer::sum);
// 统计操作
Long count = numbers.stream()
.filter(n -> n % 2 == 0)
.count();
System.out.println("Sum: " + sum); // 输出: Sum: 21
System.out.println("Even count: " + count); // 输出: Even count: 3
三、并行流性能优化
Stream API的parallel()方法可以轻松实现并行处理:
List<Integer> bigData = IntStream.range(0, 1_000_000)
.boxed()
.collect(Collectors.toList());
// 顺序流
long start = System.currentTimeMillis();
bigData.stream().map(n -> n * 2).count();
long seqTime = System.currentTimeMillis() - start;
// 并行流
start = System.currentTimeMillis();
bigData.parallelStream().map(n -> n * 2).count();
long parTime = System.currentTimeMillis() - start;
System.out.println("顺序流耗时: " + seqTime + "ms");
System.out.println("并行流耗时: " + parTime + "ms");
注意:并行流不一定总是更快,对于小数据集或存在共享状态的操作,顺序流可能更高效。
四、实际应用案例:电商数据分析
下面是一个模拟电商订单数据处理的完整示例:
class Order {
private String id;
private String customer;
private double amount;
private LocalDate date;
// 构造方法、getter/setter省略
}
public class ECommerceAnalysis {
public static void main(String[] args) {
List<Order> orders = Arrays.asList(
new Order("1001", "Alice", 120.5, LocalDate.of(2023, 5, 10)),
new Order("1002", "Bob", 89.99, LocalDate.of(2023, 5, 15)),
new Order("1003", "Alice", 45.0, LocalDate.of(2023, 6, 1)),
new Order("1004", "Charlie", 210.0, LocalDate.of(2023, 6, 5))
);
// 1. 计算总销售额
double totalSales = orders.stream()
.mapToDouble(Order::getAmount)
.sum();
// 2. 按客户分组统计
Map<String, Double> salesByCustomer = orders.stream()
.collect(Collectors.groupingBy(
Order::getCustomer,
Collectors.summingDouble(Order::getAmount)
));
// 3. 找出6月份的大额订单(>100)
List<Order> juneBigOrders = orders.stream()
.filter(o -> o.getDate().getMonth() == Month.JUNE)
.filter(o -> o.getAmount() > 100)
.collect(Collectors.toList());
System.out.println("总销售额: $" + totalSales);
System.out.println("客户销售额: " + salesByCustomer);
System.out.println("6月大额订单: " + juneBigOrders);
}
}
五、Stream使用最佳实践
- 避免在Stream中使用有副作用的操作
- 对于简单操作,传统循环可能更高效
- 注意并行流的线程安全问题
- 合理使用短路操作(findFirst/anyMatch等)提高性能
- 复杂操作考虑使用方法引用提高可读性