
痛点引入遍历集合、过滤数据、转换类型传统写法嵌套三四层forifStream 流一句话链式搞定filter → map → collect代码像流水线一样优雅今天从获取流到终结方法一篇吃透 Stream 流式计算一、Stream 流是什么1.1 一句话理解Stream 数据的流水线把「存储」和「计算」分开集合负责存Stream 负责算1.2 为什么需要 Stream没有 Stream传统方式 1. 遍历集合 → for 循环 2. 过滤数据 → if 判断 3. 转换数据 → 新建集合 4. 统计结果 → 再次循环 → 代码又长又乱 有了 Stream流式 list.stream() .filter(x - x 10) // 过滤 .map(x - x * 2) // 转换 .forEach(System.out::println); // 输出 → 一行链式调用清晰优雅 ✅1.3 ⚠️ 核心特性特性说明不存数据Stream 本身不存储元素不修改源不会改变原来的集合数据延迟执行遇到终结方法才真正计算只能用一次一个流操作过一次就不能再用了二、Stream 流的获取方式 2.1 三种获取方式速查数据来源获取方式示例Collection 集合✅list.stream()Map 集合⚠️ 不能直接获取先变单列keySet().stream()数组Stream.of(数组)Stream.of(1, 2, 3)2.2 代码示例importjava.util.*;importjava.util.stream.Stream;publicclassDemo01{publicstaticvoidmain(String[]args){// 1. 单列集合 → 直接 .stream()ArrayListIntegerlistnewArrayList();Collections.addAll(list,1,2,3,4,5);StreamIntegerstream1list.stream();// 2. 双列集合 Map → 不能直接获取先变成单列HashMapString,StringmapnewHashMap();map.put(书源,挨打);map.put(苏澳,抗揍);StreamStringkeyStreammap.keySet().stream();// 键流StreamStringvalueStreammap.values().stream();// 值流StreamMap.EntryString,StringentryStreammap.entrySet().stream();// 键值对流// 3. 数组 → Stream.of()String[]arr{书源,苏澳,张慧杰};StreamStringstream3Stream.of(arr);// 也可以直接传多个值StreamIntegerstream4Stream.of(10,20,30);}}三、Stream 方法分类 3.1 终结方法 vs 非终结方法类型调用后返回值能否继续调用示例非终结方法还是 Stream✅ 可以链式调用filter/map/limit/skip终结方法不再是 Stream❌ 流结束不能再用了forEach/count/collect3.2 流水线类比数据源集合/数组 ↓ .stream() 非终结方法1filter 过滤 ↓ 还是 Stream 非终结方法2map 转换 ↓ 还是 Stream 终结方法forEach 输出 ↓ 流结束四、非终结方法详解 4.1 filter —— 条件过滤作用根据断言型函数式接口保留判断为true的元素。importjava.util.*;importjava.util.stream.Stream;publicclassFilterDemo{publicstaticvoidmain(String[]args){ArrayListStringnamesnewArrayList();Collections.addAll(names,书源,苏澳,苏凹,叶问-书源,挨打-苏澳,韩凯胜,张慧杰);// filter保留名字长度 2 的元素names.stream().filter(x-x.length()2)// 过滤.forEach(System.out::println);// 输出System.out.println(---);// 可以链式调用多个 filternames.stream().filter(x-x.length()2)// 长度 2.filter(x-x.startsWith(挨打))// 以挨打开头.forEach(System.out::println);// 挨打-苏澳}}4.2 map —— 数据转换作用根据函数型接口将流中每个元素从 T 类型转换为 R 类型。publicclassMapDemo{publicstaticvoidmain(String[]args){ArrayListStringnamesnewArrayList();Collections.addAll(names,书源,苏澳,张慧杰);// map名字 → 名字的长度names.stream().map(x-x.length())// String → Integer.forEach(System.out::println);// 2 2 3System.out.println(---);// map filter 组合 ⭐names.stream().map(String::toUpperCase)// 转大写.filter(x-x.length()2)// 过滤.forEach(System.out::println);}}4.3 limit —— 截取前 n 个作用只取流中的前n个元素。// limit(3)只取前3个names.stream().limit(3).forEach(System.out::println);// 书源 苏澳 苏凹4.4 skip —— 跳过前 n 个作用跳过前n个取剩余的元素。// skip(3)跳过前3个取后面names.stream().skip(3).forEach(System.out::println);// 叶问-书源 挨打-苏澳 韩凯胜 张慧杰4.5 concat —— 拼接流作用把两个流合并成一个流。importjava.util.stream.Stream;publicclassConcatDemo{publicstaticvoidmain(String[]args){StreamStringstream1Stream.of(书源,苏澳);StreamStringstream2Stream.of(张慧杰,韩凯胜);// 拼接两个流Stream.concat(stream1,stream2).forEach(System.out::println);// 输出书源 苏澳 张慧杰 韩凯胜}}4.6 非终结方法速查表 方法参数类型作用示例filterPredicate过滤保留 true.filter(x - x 10)mapFunction转换类型.map(x - x.length())limitlong截取前 n 个.limit(3)skiplong跳过前 n 个.skip(2)concat2个Stream拼接两个流Stream.concat(s1, s2)五、终结方法详解 5.1 forEach —— 遍历输出作用用 Consumer 消费流中的每个元素。调用后流结束names.stream().forEach(x-System.out.println(x));// 或方法引用names.stream().forEach(System.out::println);5.2 count —— 统计个数作用返回流中元素的个数。调用后流结束longcountnames.stream().count();System.out.println(总共有count 人);5.3 collect —— 收集成集合 ⭐作用把流操作的结果收集到集合中List / Set / Map。importjava.util.*;importjava.util.stream.Collectors;publicclassCollectDemo{publicstaticvoidmain(String[]args){ArrayListStringnamesnewArrayList();Collections.addAll(names,书源,苏澳,苏凹,叶问-书源,挨打-苏澳);// 收集成 ListListStringresultnames.stream().filter(x-x.length()2).collect(Collectors.toList());System.out.println(result);// [叶问-书源, 挨打-苏澳]}}5.4 终结方法速查表 方法返回值作用forEach(Consumer)void遍历消费每个元素count()long统计元素个数collect(Collector)集合收集成 List/Set/Map六、Stream 核心规则 ⚠️6.1 一个流只能用一次StreamStringstreamnames.stream();// 第一次操作 ✅stream.forEach(System.out::println);// 第二次操作 ❌ 报错stream.forEach(System.out::println);// 报错stream has already been operated upon or closed解决方案重新获取一个新的流对象。// ✅ 每次操作重新获取names.stream().filter(x-x.length()2).forEach(System.out::println);names.stream().map(x-x.length()).forEach(System.out::println);6.2 延迟执行没有终结方法 → 不会执行 names.stream().filter(x - x 0); // 什么都没做 有终结方法 → 才会执行 ✅ names.stream().filter(x - x 0).count(); // 现在才计算七、实战Stream 经典操作 7.1 案例需求importjava.util.*;importjava.util.stream.Collectors;publicclassStreamPractice{publicstaticvoidmain(String[]args){ArrayListIntegerscoresnewArrayList();Collections.addAll(scores,88,95,60,72,45,100,59,85);// 1. 过滤出及格60的分数 → 升序排列 → 输出System.out.print(及格分数);scores.stream().filter(x-x60).sorted().forEach(x-System.out.print(x ));System.out.println();// 2. 统计有多少人不及格longfailCountscores.stream().filter(x-x60).count();System.out.println(不及格人数failCount);// 3. 给每个及格的人加 5 分加分鼓励→ 收集成新集合ListIntegerbonusscores.stream().filter(x-x60).map(x-x5)// 每人加5分.collect(Collectors.toList());System.out.println(加分后bonus);}}运行结果及格分数60 72 85 88 95 100 不及格人数2 加分后[93, 100, 65, 77, 105, 90]7.2 链式调用的优雅传统写法嵌套多行 for (Integer x : scores) { if (x 60) { newList.add(x 5); } } Collections.sort(newList); Stream 写法一行链式 scores.stream() .filter(x - x 60) .map(x - x 5) .sorted() .collect(Collectors.toList());本篇总结 Stream 概念数据流水线集合存储 Stream 计算分工明确获取方式list.stream()/map.keySet().stream()/Stream.of(数组)方法分类非终结返回 Stream可链式vs 终结结束流不可再用filter断言型过滤保留 true 的元素可多次链式调用map函数型转换T → R改变流中元素的类型limit / skip✂️limit 截取前 n 个skip 跳过前 n 个concatStream.concat(s1, s2)拼接两个流forEach / count / collect遍历输出、统计个数、收集成集合一个流只能用一次⚠️操作过就关闭需重新获取作者书源丶发布平台CSDN