代理网站建设,虚拟主机免费空间,wordpress防广告屏蔽,建设网站哪家公司比较好作者#xff1a;Howie_Y#xff0c;系原创投稿主页#xff1a;www.jianshu.com/u/79638e5f0743Java 8 发布至今也已经好几年过去#xff0c;如今 Java 也已经向 11 迈去#xff0c;但是 Java 8 作出的改变可以说是革命性的#xff0c;影响足够深远#xff0c;学习 Java …作者Howie_Y系原创投稿主页www.jianshu.com/u/79638e5f0743Java 8 发布至今也已经好几年过去如今 Java 也已经向 11 迈去但是 Java 8 作出的改变可以说是革命性的影响足够深远学习 Java 8 应该是 Java 开发者的必修课。今天给大家带来 Java 8 Stream 讲解为什么直接讲这个是因为只要你学完立刻就能上手并能让它在你的代码中大展身手。值得注意的是学习 Stream 之前必须先学习 lambda 的相关知识。本文也假设读者已经掌握 lambda 的相关知识。本篇文章主要内容介绍 Stream 以及 Stream 是如何处理集合的介绍 Stream 与集合的关系与区别Stream 的基本方法介绍一. 什么是 StreamStream 中文称为 “流”通过将集合转换为这么一种叫做 “流” 的元素序列通过声明性方式能够对集合中的每个元素进行一系列并行或串行的流水线操作。换句话说你只需要告诉流你的要求流便会在背后自行根据要求对元素进行处理而你只需要 “坐享其成”。二. 流操作 整个流操作就是一条流水线将元素放在流水线上一个个地进行处理。其中数据源便是原始集合然后将如 List的集合转换为 Stream类型的流并对流进行一系列的中间操作比如过滤保留部分元素、对元素进行排序、类型转换等最后再进行一个终端操作可以把 Stream 转换回集合类型也可以直接对其中的各个元素进行处理比如打印、比如计算总数、计算最大值等等很重要的一点是很多流操作本身就会返回一个流所以多个操作可以直接连接起来我们来看看一条 Stream 操作的代码 如果是以前进行这么一系列操作你需要做个迭代器或者 foreach 循环然后遍历一步步地亲力亲为地去完成这些操作但是如果使用流你便可以直接声明式地下指令流会帮你完成这些操作。有没有想到什么类似的是的就像 SQL 语句一样 select username from user where id 1你只要说明“我需要 id 是 1 (id 1)的用户(user)的用户名(username )”那么就可以得到自己想要的数据而不需要自己亲自去数据库里面循环遍历查找。三. 流与集合什么时候计算Stream 和集合的其中一个差异在于什么时候进行计算。一个集合它会包含当前数据结构中所有的值你可以随时增删但是集合里面的元素毫无疑问地都是已经计算好了的。流则是按需计算按照使用者的需要计算数据你可以想象我们通过搜索引擎进行搜索搜索出来的条目并不是全部呈现出来的而且先显示最符合的前 10 条或者前 20 条只有在点击 “下一页” 的时候才会再输出新的 10 条。再比方在线观看电影和你硬盘里面的电影也是差不多的道理。外部迭代和内部迭代Stream 和集合的另一个差异在于迭代。我们可以把集合比作一个工厂的仓库一开始工厂比较落后要对货物作什么修改只能工人亲自走进仓库对货物进行处理有时候还要将处理后的货物放到一个新的仓库里面。在这个时期我们需要亲自去做迭代一个个地找到需要的货物并进行处理这叫做外部迭代。后来工厂发展了起来配备了流水线作业只要根据需求设计出相应的流水线然后工人只要把货物放到流水线上就可以等着接收成果了而且流水线还可以根据要求直接把货物输送到相应的仓库。这就叫做内部迭代流水线已经帮你把迭代给完成了你只需要说要干什么就可以了(即设计出合理的流水线)。Java 8 引入 Stream 很大程度是因为流的内部迭代可以自动选择一种合适你硬件的数据表示和并行实现而以往程序员自己进行 foreach 之类的时候则需要自己去管理并行等问题。一次性的流流和迭代器类似只能迭代一次。Stream stream list.stream().map(Person::getName).sorted().limit(10);List newList stream.collect(toList());List newList2 stream.collect(toList());上面代码中第三行会报错因为第二行已经使用过这个流这个流已经被消费掉了四. 方法介绍开始实战首先我们先创建一个 Person 泛型的 ListList list new ArrayList();list.add(new Person(jack, 20));list.add(new Person(mike, 25));list.add(new Person(tom, 30));Person 类包含年龄和姓名两个成员变量private String name;private int age;1. stream() / parallelStream()最常用到的方法将集合转换为流List list new ArrayList();// return Streamlist.stream();而 parallelStream() 是并行流方法能够让数据集执行并行操作后面会更详细地讲解2. filter(T - boolean)保留 boolean 为 true 的元素保留年龄为 20 的 person 元素list list.stream().filter(person - person.getAge() 20).collect(toList());打印输出 [Person{namejack, age20}]collect(toList()) 可以把流转换为 List 类型这个以后会讲解3. distinct()去除重复元素这个方法是通过类的 equals 方法来判断两个元素是否相等的如例子中的 Person 类需要先定义好 equals 方法不然类似[Person{namejack, age20}, Person{namejack, age20}] 这样的情况是不会处理的4. sorted() / sorted((T, T) - int)如果流中的元素的类实现了 Comparable 接口即有自己的排序规则那么可以直接调用 sorted() 方法对元素进行排序如 Stream反之, 需要调用 sorted((T, T) - int) 实现 Comparator 接口根据年龄大小来比较list list.stream().sorted((p1, p2) - p1.getAge() - p2.getAge()).collect(toList());当然这个可以简化为list list.stream().sorted(Comparator.comparingInt(Person::getAge)).collect(toList());5. limit(long n)返回前 n 个元素list list.stream().limit(2).collect(toList());打印输出 [Person{namejack, age20}, Person{namemike, age25}]6. skip(long n)去除前 n 个元素list list.stream().skip(2).collect(toList());打印输出 [Person{nametom, age30}]tips:用在 limit(n) 前面时先去除前 m 个元素再返回剩余元素的前 n 个元素limit(n) 用在 skip(m) 前面时先返回前 n 个元素再在剩余的 n 个元素中去除 m 个元素list list.stream().limit(2).skip(1).collect(toList());打印输出 [Person{namemike, age25}]7. map(T - R)将流中的每一个元素 T 映射为 R(类似类型转换)List newlist list.stream().map(Person::getName).collect(toList());newlist 里面的元素为 list 中每一个 Person 对象的 name 变量8. flatMap(T - Stream)将流中的每一个元素 T 映射为一个流再把每一个流连接成为一个流List list new ArrayList();list.add(aaa bbb ccc);list.add(ddd eee fff);list.add(ggg hhh iii);list list.stream().map(s - s.split( )).flatMap(Arrays::stream).collect(toList());上面例子中我们的目的是把 List 中每个字符串元素以 分割开变成一个新的 List。首先 map 方法分割每个字符串元素但此时流的类型为 Stream因为 split 方法返回的是 String[ ] 类型所以我们需要使用 flatMap 方法先使用Arrays::stream将每个 String[ ] 元素变成一个 Stream流然后 flatMap 会将每一个流连接成为一个流最终返回我们需要的 Stream9. anyMatch(T - boolean)流中是否有一个元素匹配给定的 T - boolean 条件是否存在一个 person 对象的 age 等于 20boolean b list.stream().anyMatch(person - person.getAge() 20);10. allMatch(T - boolean)流中是否所有元素都匹配给定的 T - boolean 条件11. noneMatch(T - boolean)流中是否没有元素匹配给定的 T - boolean 条件12. findAny() 和 findFirst()findAny()找到其中一个元素 (使用 stream() 时找到的是第一个元素使用 parallelStream() 并行时找到的是其中一个元素)findFirst()找到第一个元素值得注意的是这两个方法返回的是一个 Optional对象它是一个容器类能代表一个值存在或不存在这个后面会讲到13. reduce((T, T) - T) 和 reduce(T, (T, T) - T)用于组合流中的元素如求和求积求最大值等计算年龄总和int sum list.stream().map(Person::getAge).reduce(0, (a, b) - a b);与之相同:int sum list.stream().map(Person::getAge).reduce(0, Integer::sum);其中reduce 第一个参数 0 代表起始值为 0lambda (a, b) - a b 即将两值相加产生一个新值。同样地计算年龄总乘积int sum list.stream().map(Person::getAge).reduce(1, (a, b) - a * b);当然也可以Optional sum list.stream().map(Person::getAge).reduce(Integer::sum);即不接受任何起始值但因为没有初始值需要考虑结果可能不存在的情况因此返回的是 Optional 类型。13. count()返回流中元素个数结果为 long 类型14. collect()收集方法我们很常用的是 collect(toList())当然还有 collect(toSet()) 等参数是一个收集器接口这个后面会另外讲。15. forEach()返回结果为 void很明显我们可以通过它来干什么了比方说### 16. unordered()还有这个比较不起眼的方法#返回一个等效的无序流当然如果流本身就是无序的话那可能就会直接返回其本身打印各个元素list.stream().forEach(System.out::println);再比如说 MyBatis 里面访问数据库的 mapper 方法向数据库插入新元素list.stream().forEach(PersonMapper::insertPerson);推荐大而全的【后端技术精选】