Java——Stream流
平时处理集合、数组是不是都这么写定义一个 List然后写个 for 循环遍历加 if 判断过滤数据再把符合条件的装进新集合最后再循环输出这样写十分复杂自从 Java 8 出了 Stream 流之后这一切都变了。以前五六行、十几行才能做完的事现在一行代码搞定。过滤、去重、排序、映射、统计、分组、收集…… 所有你能想到的集合操作Stream 流几乎都能一条龙解决。一、Stream定义Stream 不是集合不是数据结构它不存数据它只是一个 “加工工具”你可以把它理解成工厂流水线。集合 / 数组 → 原材料Stream → 流水线中间操作过滤、去重、排序 → 加工步骤终结操作输出、收集、统计 → 成品出厂它的工作流程特别简单把集合 / 数组变成一条 “流”在流上做各种操作想怎么加工就怎么加工最后拿到你想要的结果而且 Stream 有一个很重要的特点用完就丢只能用一次。就像矿泉水你打开喝了就没了不能倒回去再喝一遍。再记住一句话Stream 只负责处理数据不改变原数据。你原来的集合是什么样处理完还是什么样不会被修改这一点特别安全。二、Stream的优点1. 代码简洁以前遍历过滤一个集合ListString list new ArrayList(); for (String s : oldList) { if (s ! null s.length() 3) { list.add(s); } }用 StreamListString list oldList.stream() .filter(s - s ! null s.length() 3) .collect(Collectors.toList());2. 支持链式编程list.stream() .filter(...) .map(...) .distinct() .sorted() .collect(...);从上到下一步一步 代码一目了然。三、Stream 最核心的两个概念用 Stream 之前需要记住两个词中间操作、终结操作1. 中间操作加工比如过滤 filter、映射 map、去重 distinct、限制 limit、跳过 skip、排序 sorted特点可以连着写多个不会真正执行就像你在流水线设置好加工步骤机器还没开动2. 终结操作出厂比如遍历 forEach、收集 collect、计数 count、判断 anyMatch、转数组 toArray特点只要一执行整个流才开始跑执行完流就关闭了不能再用一句话总结只有调用终结操作前面的中间操作才会执行不调用终结操作等于啥也没干。四、第一步怎么获取 Stream 流3 种最常用方式想使用 Stream第一步必须先把数据变成 “流”。常用的就 3 种记这 3 种足够用。1. 集合 Collection 直接获取最常用List、Set 都能用ListString list new ArrayList(); StreamString stream list.stream(); StreamString parallelStream list.parallelStream();2. 数组用 Arrays.stream ()String[] arr {张三,李四,王五}; StreamString stream Arrays.stream(arr);3. 零散数据用 Stream.of ()StreamString stream Stream.of(张三,李四,王五,赵六);五、Stream 常用中间操作1. filter过滤作用只留下符合条件的数据参数一个返回 boolean 的条件true 留下false 扔掉例子过滤出长度大于 3 的字符串ListString list Stream.of(aa,bbb,cccc,ddddd) .filter(s - s.length() 3) .collect(Collectors.toList()); // 结果cccc、ddddd2. map转换作用把一种数据转成另一种数据比如String 转 Integer、对象转名字、对象转 ID、数字转平方例子 1字符串转长度ListInteger lengths Stream.of(张三,张三丰,孙悟空) .map(s - s.length()) .collect(Collectors.toList()); // 结果2、3、3例子 2用户对象转用户名ListString names userList.stream() .map(user - user.getName()) .collect(Collectors.toList());3. distinct去重作用自动去掉重复数据底层用的 equals () 判断简单粗暴。ListInteger list Stream.of(1,2,2,3,3,3) .distinct() .collect(Collectors.toList()); // 结果1、2、34. sorted排序作用给数据排序两种用法无参自然排序数字从小到大、字符串按字典序有参自定义排序例子 1自然排序ListInteger list Stream.of(3,1,5,2,4) .sorted() .collect(Collectors.toList()); // 1、2、3、4、5例子 2倒序.sorted((a,b) - b - a)例子 3按对象字段排序.sorted(Comparator.comparing(User::getAge))5. limit限制取前几个作用只取前 N 个ListInteger list Stream.of(1,2,3,4,5) .limit(3) .collect(Collectors.toList()); // 1、2、36. skip跳过前几个作用跳过前 N 个取后面的ListInteger list Stream.of(1,2,3,4,5) .skip(2) .collect(Collectors.toList()); // 3、4、5六、Stream 常用终结操作执行才是硬道理中间操作设置完必须调用终结操作否则代码不执行1. forEach遍历作用一个一个拿出来处理Stream.of(张三,李四).forEach(s - System.out.println(s));2. collect收集作用把流转成集合、字符串、数组这是最强大的终结操作必须会。常用收集方式转 ListCollectors.toList()转 SetCollectors.toSet()转 MapCollectors.toMap(键,值)拼接字符串Collectors.joining(,)分组Collectors.groupingBy(字段)统计Collectors.counting()、Collectors.summingInt()3. count计数作用统计流里有多少个元素long count Stream.of(1,2,3).count(); // 34. anyMatch任意一个匹配作用只要有一个符合条件就返回 trueboolean has Stream.of(1,2,3).anyMatch(s - s 2); // true5. allMatch全部匹配作用所有元素都符合条件才返回 true6. noneMatch全都不匹配作用一个都不符合才返回 true7. findFirst找第一个作用返回第一个元素OptionalString first Stream.of(a,b).findFirst();8. toArray转数组作用流转数组String[] arr Stream.of(a,b).toArray(String[]::new);七、Collectors 工具类Stream 最强辅助1. 转 List / Setcollect(Collectors.toList()); collect(Collectors.toSet());2. 转 Map注意键不能重复否则报错。MapInteger, User map userList.stream() .collect(Collectors.toMap(User::getId, user - user));3. 字符串拼接把所有元素用符号连起来超级好用。String str Stream.of(张三,李四,王五) .collect(Collectors.joining(,)); // 张三,李四,王五4. 分组按某个字段分组比如按年龄、性别、部门。MapInteger, ListUser map userList.stream() .collect(Collectors.groupingBy(User::getAge));结果key 是年龄value 是这个年龄的所有人。5. 统计最大值、最小值、平均值、总和// 总和 int sum userList.stream().collect(Collectors.summingInt(User::getAge)); // 最大值 OptionalInt max userList.stream().mapToInt(User::getAge).max(); // 平均值 double avg userList.stream().mapToInt(User::getAge).average().orElse(0);八、真实案例案例 1过滤 转换 去重 排序 收集需求从用户列表中过滤出年龄大于 18 岁的提取名字去重按字典序排序最后转成 List。ListString result userList.stream() .filter(user - user.getAge() 18) .map(User::getName) .distinct() .sorted() .collect(Collectors.toList());案例 2根据条件判断是否存在数据boolean has userList.stream() .anyMatch(user - 张三.equals(user.getName()));案例 3把 List 转成用逗号分隔的字符串String str list.stream().collect(Collectors.joining(,));案例 4根据性别分组MapString, ListUser group userList.stream() .collect(Collectors.groupingBy(User::getSex));九、Stream 和 普通 for 循环怎么选简单遍历、简单逻辑→ for 循环和 Stream 都行过滤、转换、去重、排序、统计、分组→ 优先 Stream代码简洁极度追求性能、超小数据量→ for 循环稍微快一丢丢但几乎可以忽略复杂嵌套逻辑、多跳出条件→ for 循环更清晰简单说能使用 Stream 的场景尽量用 Stream代码好看、好维护、好改。十二、总结Stream 是数据加工工具不存数据不修改原数据流只能用一次用完即关闭中间操作不执行只有终结操作才触发执行filter 过滤、map 转换、distinct 去重、sorted 排序collect 收集是最强大的终结操作Collectors 可以转 List、Set、Map、分组、拼接、统计并行流适合大数据量处理不要在 Stream 里修改外部变量toMap 注意键重复问题能用 Stream 就用 Stream代码简洁易维护