Collection.stream()
是 Java 8 函数式编程的核心,它提供了声明式处理集合数据的能力。本文将深入探讨其使用场景、高级技巧和实战应用。
一、核心概念与基础
1. Stream 的特点
- 非存储:不存储数据,只是数据的视图
- 函数式操作:支持 Lambda 表达式和方法引用
- 惰性求值:中间操作延迟执行
- 可并行:支持多线程处理
2. 创建 Stream 的方式
ini
// 从集合创建
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream1 = list.stream();
// 从数组创建
String[] array = {"a", "b", "c"};
Stream<String> stream2 = Arrays.stream(array);
// 使用 Stream.of
Stream<String> stream3 = Stream.of("a", "b", "c");
// 生成无限流
Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 1);
二、核心使用场景
1. 数据过滤与转换
scss
List<User> users = getUserList();
// 过滤+转换组合操作
List<String> names = users.stream()
.filter(user -> user.getAge() > 18) // 过滤成年用户
.map(User::getName) // 提取姓名
.filter(name -> name.startsWith("张")) // 过滤姓氏
.collect(Collectors.toList());
2. 数据统计与分析
less
List<Order> orders = getOrderList();
// 多维度统计
Map<String, DoubleSummaryStatistics> stats = orders.stream()
.collect(Collectors.groupingBy(
Order::getCategory,
Collectors.summarizingDouble(Order::getAmount)
));
stats.forEach((category, stat) -> {
System.out.println(category + ": " +
"数量=" + stat.getCount() +
", 总额=" + stat.getSum() +
", 平均=" + stat.getAverage());
});
3. 复杂数据分组
swift
List<Employee> employees = getEmployees();
// 多级分组
Map<Department, Map<String, List<Employee>>> grouped = employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.groupingBy(emp -> {
if (emp.getSalary() > 10000) return "高薪";
else if (emp.getSalary() > 5000) return "中薪";
else return "低薪";
})
));
4. 并行数据处理
ini
List<Data> largeData = getLargeData();
// 并行处理大数据集
Map<String, List<Data>> result = largeData.parallelStream()
.filter(data -> data.isValid())
.collect(Collectors.groupingByConcurrent(Data::getType));
三、深度使用技巧
1. 自定义 Collector
typescript
// 自定义统计收集器
public class CustomStatsCollector implements Collector<Integer, int[], CustomStats> {
@Override
public Supplier<int[]> supplier() {
return () -> new int[4]; // [count, sum, min, max]
}
@Override
public BiConsumer<int[], Integer> accumulator() {
return (arr, num) -> {
arr[0]++; // count
arr[1] += num; // sum
arr[2] = Math.min(arr[2], num); // min
arr[3] = Math.max(arr[3], num); // max
};
}
@Override
public BinaryOperator<int[]> combiner() {
return (arr1, arr2) -> new int[]{
arr1[0] + arr2[0],
arr1[1] + arr2[1],
Math.min(arr1[2], arr2[2]),
Math.max(arr1[3], arr2[3])
};
}
@Override
public Function<int[], CustomStats> finisher() {
return arr -> new CustomStats(arr[0], arr[1], arr[2], arr[3]);
}
@Override
public Set<Characteristics> characteristics() {
return Set.of(Characteristics.CONCURRENT);
}
}
2. 异常处理技巧
rust
List<String> numbers = Arrays.asList("1", "2", "abc", "4");
// 安全的数值转换
List<Integer> result = numbers.stream()
.map(str -> {
try {
return Integer.parseInt(str);
} catch (NumberFormatException e) {
return null; // 或者使用 Optional
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
3. 性能优化模式
scss
// 使用 primitive stream 避免装箱开销
IntStream intStream = list.stream().mapToInt(Integer::intValue);
// 批量处理避免多次流操作
public void processInBatches(List<Data> dataList, int batchSize) {
IntStream.range(0, (dataList.size() + batchSize - 1) / batchSize)
.mapToObj(i -> dataList.subList(i * batchSize,
Math.min((i + 1) * batchSize, dataList.size())))
.parallel()
.forEach(this::processBatch);
}
四、实战案例
案例1:电商订单分析
less
public class OrderAnalyzer {
public void analyzeOrders(List<Order> orders) {
// 1. 销售额统计
Map<String, Double> salesByCategory = orders.stream()
.collect(Collectors.groupingBy(
Order::getCategory,
Collectors.summingDouble(Order::getTotalAmount)
));
// 2. 热销商品排名
Map<String, Long> productRank = orders.stream()
.flatMap(order -> order.getItems().stream())
.collect(Collectors.groupingBy(
OrderItem::getProductId,
Collectors.summingLong(OrderItem::getQuantity)
))
.entrySet().stream()
.sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.limit(10)
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
LinkedHashMap::new
));
// 3. 用户购买行为分析
Map<String, UserBehavior> userBehavior = orders.stream()
.collect(Collectors.groupingBy(
Order::getUserId,
Collectors.collectingAndThen(
Collectors.toList(),
userOrders -> new UserBehavior(
userOrders.size(),
userOrders.stream().mapToDouble(Order::getTotalAmount).sum(),
userOrders.stream().mapToDouble(Order::getTotalAmount).average().orElse(0)
)
)
));
}
}
案例2:日志分析系统
typescript
public class LogAnalyzer {
public void analyzeLogs(List<LogEntry> logs) {
// 错误日志统计
Map<String, Map<String, Long>> errorStats = logs.stream()
.filter(log -> log.getLevel().equals("ERROR"))
.collect(Collectors.groupingBy(
LogEntry::getService,
Collectors.groupingBy(
LogEntry::getErrorCode,
Collectors.counting()
)
));
// 性能监控
Map<String, DoubleSummaryStatistics> performanceStats = logs.stream()
.filter(log -> log.getResponseTime() > 0)
.collect(Collectors.groupingBy(
LogEntry::getEndpoint,
Collectors.summarizingDouble(LogEntry::getResponseTime)
));
// 异常检测
List<LogEntry> anomalies = logs.stream()
.filter(log -> isAnomaly(log, performanceStats))
.collect(Collectors.toList());
}
private boolean isAnomaly(LogEntry log, Map<String, DoubleSummaryStatistics> stats) {
DoubleSummaryStatistics stat = stats.get(log.getEndpoint());
return stat != null && log.getResponseTime() > stat.getAverage() + 3 * stat.getStandardDeviation();
}
}
案例3:社交网络分析
typescript
public class SocialNetworkAnalyzer {
public void analyzeNetwork(List<User> users) {
// 用户关系网络
Map<String, List<String>> socialGraph = users.stream()
.collect(Collectors.toMap(
User::getId,
User::getFriends
));
// 影响力分析
Map<String, Integer> influenceScores = users.stream()
.collect(Collectors.toMap(
User::getId,
user -> calculateInfluenceScore(user, socialGraph)
));
// 社区发现
List<Set<String>> communities = detectCommunities(socialGraph);
}
private int calculateInfluenceScore(User user, Map<String, List<String>> graph) {
return graph.get(user.getId()).stream()
.mapToInt(friendId -> graph.get(friendId).size())
.sum();
}
}
五、最佳实践与注意事项
1. 性能考虑
scss
// 好的实践:使用 primitive streams
IntStream intStream = list.stream().mapToInt(Integer::intValue);
// 避免在流中执行耗时操作
List<Result> results = dataList.stream()
.map(data -> {
// 避免:每个元素都进行网络请求或数据库操作
return expensiveOperation(data);
})
.collect(Collectors.toList());
// 改为:批量处理或使用并行流
List<Result> results = dataList.parallelStream()
.map(this::expensiveOperation)
.collect(Collectors.toList());
2. 可读性维护
scss
// 使用方法引用提升可读性
List<String> names = users.stream()
.filter(User::isActive)
.map(User::getFullName)
.collect(Collectors.toList());
// 复杂操作提取为方法
List<Report> reports = data.stream()
.map(this::transformToReport)
.filter(this::validateReport)
.collect(Collectors.toList());
3. 错误处理
kotlin
// 统一的异常处理策略
public <T, R> List<R> safeStreamProcess(List<T> list, Function<T, R> mapper) {
return list.stream()
.map(item -> {
try {
return mapper.apply(item);
} catch (Exception e) {
log.error("Processing failed for item: {}", item, e);
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
六、总结
适用场景
- ✅ 数据转换和过滤
- ✅ 统计分析和聚合
- ✅ 复杂数据分组
- ✅ 并行数据处理
- ✅ 声明式编程场景
不适用场景
- ❌ 需要索引访问的复杂算法
- ❌ 频繁修改集合内容的操作
- ❌ 极度性能敏感的场景(需要手动优化)
- ❌ 复杂的异常处理流程
性能建议
- 小数据集(<1000):顺序流足够
- 中等数据集(1000-10000):根据操作复杂度选择
- 大数据集(>10000):优先考虑并行流
- IO密集型:谨慎使用并行流(可能适得其反)