在使用Java Stream API时,虽然它提供了强大的功能来简化集合操作,但也存在一些常见的“坑”需要注意。以下是详细的避坑指南:
forEach
、collect
等终端操作),就不能再次使用。List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = numbers.stream();
stream.forEach(System.out::println); // 第一次消费
stream.forEach(System.out::println); // 抛出IllegalStateException
parallelStream
)在多线程环境下可能会引发线程安全问题,尤其是在共享可变状态时。ConcurrentHashMap
)。List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> result = new ArrayList<>();
numbers.parallelStream().forEach(result::add); // 线程不安全
filter
、map
)是延迟执行的,只有在终端操作(如collect
、forEach
)调用时才会真正执行。List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = numbers.stream().filter(n -> {
System.out.println("Filtering: " + n);
return n > 2;
}); // 不会立即执行
stream.forEach(System.out::println); // 执行过滤和输出
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 传统循环
for (int n : numbers) {
if (n > 2) {
System.out.println(n);
}
}
// Stream
numbers.stream().filter(n -> n > 2).forEach(System.out::println);
null
,可能会引发NullPointerException
。null
,或者使用Optional
来处理可能的null
值。List<String> list = Arrays.asList("a", "b", null, "c");
list.stream().filter(Objects::nonNull).forEach(System.out::println);
sorted
操作可能会改变Stream的顺序,尤其是在并行流中。Comparator
来明确排序规则。List<Integer> numbers = Arrays.asList(5, 3, 1, 4, 2);
numbers.stream().sorted().forEach(System.out::println); // 1, 2, 3, 4, 5
Stream.generate
和Stream.iterate
可以创建无限流,如果不加以限制,可能会导致程序无法终止。limit
来限制流的大小,或者使用takeWhile
来在满足条件时终止流。Stream.generate(Math::random).limit(10).forEach(System.out::println);
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = 0;
numbers.stream().forEach(n -> sum += n); // 不推荐
int total = numbers.stream().reduce(0, Integer::sum); // 推荐
flatMap
使用flatMap
用于将多个流合并为一个流,但如果使用不当,可能会导致性能问题或逻辑错误。flatMap
中的映射函数返回的是流,并且流的元素类型正确。List<List<Integer>> nestedList = Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4),
Arrays.asList(5, 6)
);
List<Integer> flatList = nestedList.stream()
.flatMap(List::stream)
.collect(Collectors.toList()); // [1, 2, 3, 4, 5, 6]
reduce
操作reduce
操作可能会因为初始值或累加器的使用不当而导致错误。List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream().reduce(0, Integer::sum); // 正确
Java Stream API 提供了强大的功能,但也需要谨慎使用。理解Stream的特性和潜在问题,可以帮助我们避免常见的陷阱,编写出高效、安全的代码。