Java Stream 常用中间操作与终端操作速览
一 常用中间操作
-
sorted() / sorted(Comparator) :对流元素排序,支持自然排序或自定义比较器;适用于需要有序输出的场景,如排行榜、时间线。注意排序是有状态操作,大数据量会缓存与比较开销上升。
示例:javaList<String> words = Arrays.asList("banana","apple","cherry"); List<String> asc = words.stream().sorted().toList(); List<String> desc = words.stream().sorted(Comparator.reverseOrder()).toList(); -
distinct() :去除重复元素,依赖 equals/hashCode ;适用于去重后再聚合或关联。
示例:javaList<Integer> nums = Arrays.asList(1,2,2,3,4,4,5); List<Integer> uniq = nums.stream().distinct().toList(); // [1,2,3,4,5] -
limit(long n) / skip(long n) :截取前 n 个或跳过前 n 个;常与分页、抽样、Top-N 搭配。
示例:javaList<Integer> top3 = nums.stream().limit(3).toList(); List<Integer> after2 = nums.stream().skip(2).toList(); -
flatMap(Function<? super T, Stream<? extends R>>) :将元素映射为流并扁平化为单一流;适用于"集合的嵌套结构""一对多展开"。
示例:javaList<List<Integer>> lists = Arrays.asList(Arrays.asList(1,2), Arrays.asList(3,4)); List<Integer> flat = lists.stream().flatMap(List::stream).toList(); // [1,2,3,4] -
peek(Consumer) :对每个元素执行副作用(如日志、计数),用于调试或观察流水线中间状态;注意它不保证执行时机,勿用于关键业务逻辑。
示例:javaList<String> upper = words.stream() .peek(s -> System.out.println("before: "+s)) .map(String::toUpperCase) .toList(); -
原始类型流配套映射:mapToInt/mapToLong/mapToDouble、flatMapToInt/flatMapToLong/flatMapToDouble ,避免装箱拆箱,提高数值计算性能。
示例:javaint sum = IntStream.of(1,2,3,4).sum(); // 10以上中间操作均为惰性,只有遇到终端操作才会触发执行。
二 常用终端操作
-
collect(Collector) :将流归约为集合、字符串或聚合结构;最常用收集器包括 toList/toSet/toMap/joining/counting/groupingBy/partitioningBy/maxBy/minBy/summingInt/averagingInt 。
示例:javaList<String> list = Stream.of("a","b","c").toList(); Map<String,Integer> nameLen = Stream.of("a","bb","ccc") .collect(Collectors.toMap(s -> s, String::length)); String joined = Stream.of("a","b","c").collect(Collectors.joining(", ")); Map<Integer,Long> lenCnt = Stream.of("a","bb","ccc","dd") .collect(Collectors.groupingBy(String::length, Collectors.counting())); -
forEach / forEachOrdered :遍历消费元素;并行流下如需保持顺序,使用 forEachOrdered 。
示例:javawords.stream().forEach(System.out::println); words.parallelStream().forEachOrdered(System.out::println); -
toArray() / toArray(IntFunction) :转换为数组,适合与现有 API(如 JDBC、第三方库)对接。
示例:javaString[] arr = words.stream().toArray(String[]::new); -
reduce(identity, BinaryOperator) / reduce(BinaryOperator) :将流归约为单个值;适合自定义聚合(如拼接、加权合并)。
示例:javaint sum1 = IntStream.of(1,2,3).reduce(0, Integer::sum); // 10 Optional<Integer> sum2 = Stream.of(1,2,3).reduce(Integer::sum); -
count() :计数;适合统计满足条件的元素数量。
示例:javalong n = words.stream().count(); -
min(Comparator) / max(Comparator) :求最值,返回 Optional ,需提供比较器。
示例:javaOptional<String> min = words.stream().min(String::compareTo); -
anyMatch / allMatch / noneMatch :条件匹配,返回 boolean ;适合存在性校验、全量规则校验,具备短路特性。
示例:javaboolean hasA = words.stream().anyMatch(s -> s.startsWith("a")); boolean allLen3 = words.stream().allMatch(s -> s.length() == 3); boolean noneEmpty = words.stream().noneMatch(String::isEmpty); -
findFirst / findAny :查找元素,返回 Optional ;并行流下 findAny 可能返回任意一个匹配元素,findFirst 保证顺序语义。
示例:javaOptional<String> first = words.stream().findFirst(); Optional<String> any = words.parallelStream().findAny();终端操作会触发流的实际计算,执行后流即关闭,无法再次使用。
三 选型建议与易错点
- 操作顺序影响性能:优先 filter 再 map ,尽早减少数据量;必要时使用 limit/skip 做分页或截断,减少后续计算成本。
- 有状态操作谨慎使用:sorted/distinct/limit/skip 等可能缓存或全局排序,数据量大时内存与时间开销显著。
- 并行流与顺序语义:findAny 在并行流更"随意",需要稳定顺序或首元素语义时选 findFirst ;并行下如需顺序遍历用 forEachOrdered。
- 收集器选择:构建 Map 时注意冲突合并策略(如 toMap(k,v,(o,n)->n) );仅需要拼接用 joining ,统计用 summarizingInt 等,避免重复遍历。
- 调试用 peek ,生产勿依赖:它不保证执行时机与次数,避免把关键业务副作用放在 peek 中。
- 原始类型流优先:数值聚合、统计优先用 IntStream/LongStream/DoubleStream 及配套 sum/average/max/min,减少装箱与对象分配。