说起流,我们会想起手机 ,电脑组装流水线,物流仓库商品包装流水线等等。如果把手机 ,电脑,包裹看做最终结果的话,那么加工商品前的各种零部件就可以看做数据源,而中间一系列的加工作业操作,就可以看做流的处理。

流的概念

Java Se中对于流的操作有输入输出IO流,而Java8中引入的Stream 属于Java API中的一个新成员,它允许你以声明性方式处理数据集合,Stream 使用一种类似 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。 注意这里的流操作可以看做是对集合数据的处理。

简单来说,流是一种数据渠道,用于操作数据源(集合、数组、文件等)所生产的元素序列。

源-流会使用一个提供数据的源,如集合、数组或输入|输出资源。从有序集生成流时会保留原有的顺序。由列表生成的流,其元素顺序与列表一致

元素序列-就像集合一样,流也提供了一个接口,可以访问特定元素类型的一组有序值。数据处理操作-流的数据处理功能支持类似于数据库的操作(数据筛选、过滤、排序等操作)。流水线-多个流操作本身会返回一个流,多个操作就可以链接起来,成为数据处理的一道流水线。流&集合

计算的时期

集合中数据都是计算完毕的数据,例如从数据库中查询用户记录 按用户id 查询 降序排列 然后通过list 接收用户记录,数据的计算已在放入集合前完成。

流中数据按需计算,按照使用者的需要计算数据,例如通过搜索引擎进行搜索,搜索出来的条目并不是全部呈现出来的,而且先显示最符合的前 10 条或者前 20 条,只有在点击 “下一页” 的时候,才会再输出新的 10 条。流的计算也是这样,当用户需要对应数据时,Stream 才会对其进行计算处理。

外部迭代与内部迭代

把集合比作一个工厂的仓库的话,一开始工厂硬件比较落后,要对货物作什么修改,此时工人亲自走进仓库对货物进行处理,有时候还要将处理后的货物转运到另一个仓库中。此时对于开发者来说需要亲自去做迭代,一个个地找到需要的货物,并进行处理,这叫做外部迭代。

当工厂发展起来后,配备了流水线作业,工厂只要根据需求设计出相应的流水线,然后工人只要把货物放到流水线上,就可以等着接收成果了,而且流水线还可以根据要求直接把货物输送到相应的仓库。

这就叫做内部迭代,流水线已经帮你把迭代给完成了,你只需要说要干什么就可以了(即设计出合理的流水线)。相当于 Java8 引入的Stream 对数据的处理实现了”自动化”操作。

流操作过程

整个流操作就是一条流水线,将元素放在流水线上一个个地进行处理。需要注意的是:很多流操作本身就会返回一个流,所以多个操作可以直接连接起来, 如下图这样,操作可以进行链式调用,并且并行流还可以实现数据流并行处理操作。

总的来说,流操作过程分为三个阶段:

创建借助数据源创建流对象

中间处理筛选、切片、映射、排序等中间操作

终止流匹配、汇总、分组等终止操作

流的创建

对流操作首先要创建对应的流,流的创建集中形式如下:

「1 集合创建流」

在 Java 8 中, 集合接口有两个方法来生成流:

stream() 为集合创建串行流。parallelStream() 为集合创建并行流。示例代码如下:

publicstaticvoidmain(String[] args){/*** 定义集合l1 并为集合创建串行流 */ List l1 = Arrays.asList("周星驰", "周杰伦", "周星星", "周润发");// 返回串行流 l1.stream();// 返回并行流 l1.parallelStream();}

上述操作得到的流是通过原始数据转换过来的流,除了这种流创建的基本操作外,对于流的创建还有以下几种方式。

「2 值创建流」

Stream.of(T...) : Stream.of("aa", "bb") 生成流

//值创建流 生成一个字符串流Stream stream = Stream.of("java8", "Spring", "SpringCloud");stream.forEach(System.out::println);

「3 数组创建流」

根据参数的数组类型创建对应的流。

Arrays.stream(T[ ])Arrays.stream(int[ ])Arrays.stream(double[ ])Arrays.stream(long[ ])

/*** 这里以int 为例 long double 不再举例 */ Stream stream = Arrays.stream(Arrays.asList(10, 20, 30, 40).toArray());// 根据数组索引范围创建指定Stream stream = Arrays.stream(Arrays.asList(10, 20, 30, 40).toArray(), 0, 2);

「4 文件生成流」

stream = Files.lines(Paths.get("C:\\java\\jdbc.properties"));System.out.println(stream.collect(Collectors.toList()));// 指定字符集编码stream = Files.lines(Paths.get("C:\\java\\jdbc.properties"), Charset.forName("utf-8"));System.out.println(stream.collect(Collectors.toList()));

「5 函数生成流」

两个方法:

iterate : 依次对每个新生成的值应用函数generate :接受一个函数,生成一个新的值

// 重100 开始 生成偶数流Stream.iterate(100, n -> n + 2);// 产生1-100 随机数 Stream.generate(() ->(int) (Math.random() * 100 + 1));

流中间操作

流的中间操作分为三大类:筛选切片、映射、排序。

筛选切片:类似sql 中where 条件判断的意思,对元素进行筛选操作

映射:对元素结果进行转换 ,优点类似select 字段意思或者对元素内容进行转换处理

排序:比较好理解 ,常用sql 中按字段升序 降序操作

流中间操作数据准备(这里以订单数据处理为例)

@DatapublicclassOrder{// 订单idprivate Integer id;// 订单用户idprivate Integer userId;// 订单编号private String orderNo;// 订单日期private Date orderDate;// 收货地址private String address;// 创建时间private Date createDate;// 更新时间private Date updateDate;// 订单状态 0-未支付 1-已支付 2-待发货 3-已发货 4-已接收 5-已完成private Integer status;// 是否有效 1-有效订单 0-无效订单private Integer isValid;//订单总金额private Double total;}Order order01 = new Order(1, 10, "20190301",new Date(), "上海市-浦东区", new Date(), new Date(), 4, 1, 100.0);Order order02 = new Order(2, 30, "20190302",new Date(), "北京市四惠区", new Date(), new Date(), 1, 1, 2000.0);Order order03 = new Order(3, 20, "20190303",new Date(), "北京市-朝阳区", new Date(), new Date(), 4, 1, 500.0);Order order04 = new Order(4, 40, "20190304",new Date(), "北京市-大兴区", new Date(), new Date(), 4, 1, 256.0);Order order05 = new Order(5, 40, "20190304",new Date(), "上海市-松江区", new Date(), new Date(), 4, 1, 1000.0);ordersList = Arrays.asList(order01, order02, order03, order04, order05);

筛选&切片

筛选有效订单

// 过滤有效订单ordersList.stream().filter((order) -> order.getIsValid() == 1).forEach(System.out::println);

筛选有效订单 取第一页数据(每页2条记录)

// 过滤有效订单 取第一页数据(每页2条记录) ordersList.stream().filter((order) -> order.getIsValid() == 1) .limit(2) .forEach(System.out::println);

筛选订单集合有效订单 取最后一条记录

// 过滤订单集合有效订单 取最后一条记录ordersList.stream().filter((order) -> order.getIsValid() == 1).skip(ordersList.size() - 2) // 跳过前ordersList.size()-2 记录 .forEach(System.out::println);

筛选有效订单 取第3页数据(每页2条记录)

// 过滤有效订单 取第3页数据(每页2条记录) 并打印到控制台ordersList.stream().filter((order) -> order.getIsValid() == 1).skip((3 - 1) * 2) .limit(2) .forEach(System.out::println);

筛选无效订单去除重复订单号记录

// 过滤无效订单 去除重复订单号记录 重写Order equals 与 hashCode 方法ordersList.stream().filter((order) -> order.getIsValid() == 0).distinct() .forEach(System.out::println);

映射

过滤有效订单,获取所有订单编号

//过滤有效订单,获取所有订单编号ordersList.stream().filter((order) -> order.getIsValid() == 1).map((order) -> order.getOrderNo()) .forEach(System.out::println);

过滤有效订单 ,并分离每个订单下收货地址市区信息

ordersList.stream().map(o -> o.getAddress().split("-")) .flatMap(Arrays::stream) .forEach(System.out::println);

排序

过滤有效订单 根据用户id 进行排序

//过滤有效订单 根据用户id 进行排序ordersList.stream().filter((order) -> order.getIsValid() == 1).sorted((o1, o2) -> o1.getUserId() - o2.getUserId()) .forEach(System.out::println); //或者等价写法 ordersList.stream().filter((order) -> order.getIsValid() == 1) .sorted(Comparator.comparingInt(Order::getUserId)) .forEach(System.out::println);

过滤有效订单 ,根据订单状态排序 如果订单状态相同根据订单创建时间排序

//过滤有效订单 如果订单状态相同 根据订单创建时间排序 反之根据订单状态排序ordersList.stream().filter((order) -> order.getIsValid() == 1).sorted((o1, o2) -> {if (o1.getStatus().equals(o2.getStatus())) {return o1.getCreateDate().compareTo(o2.getCreateDate()); } else {return o1.getStatus().compareTo(o2.getStatus()); }}) .forEach(System.out::println);// 等价形式ordersList.stream().filter((order) -> order.getIsValid() == 1) .sorted(Comparator.comparing(Order::getCreateDate) .thenComparing(Comparator.comparing(Order::getStatus))) .forEach(System.out::println);

流的终止操作

终止操作会从流的流水线生成结果。其结果是任何不是流的值,比如常见的List、 Integer,甚 至void等结果。对于流的终止操作,分为以下三类:

查找与匹配

筛选有效订单 匹配是否全部为已支付订单

// 筛选有效订单 匹配是否全部为已支付订单System.out.println("allMatch匹配结果:" + ordersList.stream() .filter((order) -> order.getIsValid() == 1) .allMatch((o) -> o.getStatus() != 0) );

筛选有效订单 匹配是否存在未支付订单

// 筛选有效订单 匹配是否存在未支付订单System.out.println("anyMatch匹配结果:" + ordersList.stream() .filter((order) -> order.getIsValid() == 1) .anyMatch((o) -> o.getStatus() == 0) );

筛选有效订单 全部未完成订单

// 筛选有效订单 全部未完成订单System.out.println("noneMatch匹配结果:" + ordersList.stream() .filter((order) -> order.getIsValid() == 1) .noneMatch((o) -> o.getStatus() == 5) );

筛选有效订单 返回第一条订单

// 筛选有效订单 返回第一条订单System.out.println("findAny匹配结果:"+ ordersList.stream() .filter((order) -> order.getIsValid() == 1) .findAny() .get() );

筛选所有有效订单 返回订单总数

// 筛选所有有效订单 返回订单总数System.out.println("count结果:" + ordersList.stream() .filter((order) -> order.getIsValid() == 1) .count() );

筛选有效订单 返回金额最大订单金额

// 筛选有效订单 返回金额最大订单金额System.out.println("订单金额最大值:" + ordersList.stream() .filter((order) -> order.getIsValid() == 1) .map(Order::getTotal) .max(Double::compare) .get() );

筛选有效订单 返回金额最小订单金额

// 筛选有效订单 返回金额最小订单金额System.out.println("订单金额最小值:" + ordersList.stream() .filter((order) -> order.getIsValid() == 1) .map(Order::getTotal) .min(Double::compare) .get() );

归约&收集

1 归约

将流中元素反复结合起来,得到一个值的操作

计算有效订单总金额

// 计算有效订单总金额System.out.println("有效订单总金额:" + ordersList.stream() .filter((order) -> order.getIsValid() == 1) .map(Order::getTotal) .reduce(Double::sum) .get() );

2 Collector数据收集

将流转换为其他形式,coollect 方法作为终端操作, 接收一个Collector接口的实现,用于给Stream中元素做汇总的方法。最常用的方法,把流中所有元素收集到一个 List, Set 或 Collection中。

3 集合收集

常用集合收集方法 toList、toSet、toCollection、toMap等

筛选所有有效订单 并收集订单列表

// 筛选所有有效订单并收集订单列表ordersList.stream().filter((order) -> order.getIsValid() == 1) .collect(Collectors.toList()) .forEach(System.out::println);

筛选所有有效订单并收集订单号与订单金额

// 筛选所有有效订单 并收集订单号 与 订单金额Map map=ordersList.stream().filter((order) -> order.getIsValid() == 1).collect(Collectors.toMap(Order::getOrderNo, Order::getTotal));// java8 下对map进行遍历操作 如果 Map的Key重复,会报错map.forEach((k,v)->{ System.out.println("k:"+k+":v:"+v);});

汇总

汇总操作在Stream流操作比较常见,比如计算总数,求平均等操作,常用方法如下:

相关操作如下

筛选所有有效订单 返回订单总数

System.out.println("count结果:"+ordersList.stream() .filter((order) -> order.getIsValid() == 1) .collect(Collectors.counting()) );System.out.println("count结果:"+ ordersList.stream() .filter((order) -> order.getIsValid() == 1) .count() );

返回订单总金额

System.out.println("订单总金额:"+ordersList.stream() .filter((order) -> order.getIsValid() == 1) .collect(Collectors.summarizingDouble(Order::getTotal)) );System.out.println("订单总金额:"+ ordersList.stream() .filter((order) -> order.getIsValid() == 1) .mapToDouble(Order::getTotal) .sum() );System.out.println("订单总金额:"+ ordersList.stream() .filter((order) -> order.getIsValid() == 1) .map(Order::getTotal) .reduce(Double::sum) .get() );

返回用户id=20 有效订单平均每笔消费金额

System.out.println("用户id=20 有效订单平均每笔消费金额:"+ordersList.stream() .filter((order) -> order.getIsValid() == 1) .filter((order -> order.getUserId()==20)) .collect(Collectors.averagingDouble(Order::getTotal)) );System.out.println("用户id=20 有效订单平均每笔消费金额:"+ ordersList.stream() .filter((order) -> order.getIsValid() == 1) .filter((order -> order.getUserId()==20)) .mapToDouble(Order::getTotal) .average() .getAsDouble() );System.out.println("用户id=20 有效订单平均每笔消费金额:"+ ordersList.stream() .filter((order) -> order.getIsValid() == 1) .filter((order -> order.getUserId()==20)) .collect(Collectors.summarizingDouble(Order::getTotal)) .getAverage() );

筛选所有有效订单 并计算订单总金额

System.out.println("订单总金额:"+ordersList.stream() .filter((order) -> order.getIsValid() == 1) .collect(Collectors.summingDouble(Order::getTotal)) );

最值

筛选所有有效订单 并计算最小订单金额

System.out.println("最小订单金额:"+ordersList.stream() .filter((order) -> order.getIsValid() == 1) .map(Order::getTotal) .collect(Collectors.minBy(Double::compare)) );

筛选所有有效订单 并计算最大订单金额

// 筛选所有有效订单 并计算最大订单金额System.out.println("最大订单金额:"+ordersList.stream() .filter((order) -> order.getIsValid() == 1) .map(Order::getTotal) .collect(Collectors.maxBy(Double::compare)) );

分组&分区

1 分组

groupingBy 用于将数据分组,最终返回一个 Map 类型 ,groupingBy 第二参数用于实现多级分组

根据有效订单支付状态进行分组操作

Map> g01=ordersList.stream().filter((order) -> order.getIsValid() == 1) .collect(Collectors.groupingBy(Order::getStatus));g01.forEach((status,order)->{ System.out.println("----------------"); System.out.println("订单状态:"+status); order.forEach(System.out::println);});

筛选有效订单,根据用户id 和 支付状态进行分组

Map>> g02= ordersList.stream().filter((order) -> order.getIsValid() == 1) .collect(Collectors.groupingBy(Order::getUserId, Collectors.groupingBy((o)->{if(o.getStatus()==0){return"未支付"; }elseif (o.getStatus()==1){return"已支付"; }elseif (o.getStatus()==2){return"待发货"; }elseif (o.getStatus()==3){return"已发货"; }elseif (o.getStatus()==4){return"已接收"; } else{return"已完成"; } } )) );g02.forEach((userId,m)->{ System.out.println("用户id:"+userId+"-->有效订单如下:"); m.forEach((status,os)->{ System.out.println("状态:"+status+"---订单列表如下:"); os.forEach(System.out::println); }); System.out.println("-----------------------");});

2 分区

分区与分组的区别在于,分区是按照 true 和 false 来分的,因此partitioningBy 接受的参数的 lambda 也是

T -> boolean

分区操作-筛选订单金额>1000 的有效订单

Map> g03= ordersList.stream().filter((order) -> order.getIsValid() == 1) .collect(Collectors.partitioningBy((o)->o.getTotal()>1000));g03.forEach((b,os)->{ System.out.println("分区结果:"+b+"--列表结果:"); os.forEach(System.out::println);});

拼接操作-筛选有效订单并进行拼接

String orderStr=ordersList.stream().filter((order) -> order.getIsValid() == 1) .map(Order::getOrderNo) .collect(Collectors.joining(","));System.out.println(orderStr);

流的应用

Java8引入Stream流操作,使得对元素的处理更加的方便快捷,通过Stream提供的相关方法很好的结合Lambda、函数式接口、方法引用等相关内容,使得流的处理相比较原始集合处理代码极大简化,Stream支持函数的链式调用,代码上更加紧凑同时Stream支持的元素的并行化处理提高了程序的执行性能。

对于Stream流的应用通常在集合元素数据处理上特别是对元素需要进行多次处理的情况,同时对于函数式编程的味道更加浓重,也是以后开发的一个趋势。

好了,Java8核心特性之Stream流就介绍到这里了,应该是非常详尽了,希望大家喜欢。

java8实战怎么样_Java8中你可能不知道的一些地方之Stream实战相关推荐

  1. java8中class怎么用_Java8中你可能不知道的一些地方之方法引用实战

    Java8 中引入方法引用新特性,用于简化应用对象方法的调用, 方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法. 方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的 ...

  2. java 8 lamda,Java8中你可能不知道的一些地方之Lambda表达式实战

    Java8 引入 Lambda 表达式,允许开发者将函数当成参数传递给某个方法,或者把代码本身当作数据进行处理.使用 Lambda 表达式,使得应用变得简洁而紧凑. 很多语言(Groovy.Scala ...

  3. java function void_Java8中你可能不知道的一些地方之函数式接口实战

    什么时候可以使用 Lambda?通常 Lambda 表达式是用在函数式接口上使用的.从 Java8 开始引入了函数式接口,其说明比较简单:函数式接口(Functional Interface)就是一个 ...

  4. 国际计算机思维比赛,少儿编程领域中,你所不知道的国际计算思维大赛

    原标题:少儿编程领域中,你所不知道的国际计算思维大赛 孩子学习编程,除了培养编程思维和计算思维,也能为未来应对人工智能时代打下基础.今天给大家讲的的是Bebras国际计算思维大赛,请大家持续关注坚果学 ...

  5. java8 流操作_java8中的流操作

    Stream 流是 Java 8 新提供给开发者的一组操作集合的 API,将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选.排序.聚合等.元素流在管道中经过 ...

  6. java8的表达式_java8中的Lambda表达式

    lambad表达式是一个匿名函数,既没有函数名的函数.在lambda表达式出现之前,java中更多使用的是匿名内部类所以有些刚刚接触lambda表达式的人会把lambda表达式误认为就是匿名内部类的简 ...

  7. java8 list 去重_Java8中的Stream,一行代码,让集合操作飞起来

    简介 java8也出来好久了,接口默认方法,lambda表达式,函数式接口,Date API等特性还是有必要去了解一下.比如在项目中经常用到集合,遍历集合可以试下lambda表达式,经常还要对集合进行 ...

  8. java8时间间隔计算_Java8中Instant和LocalDate来计算时间或者日期间隔

    /** * java.time.Instant * java.time.Duration * Instant 默认使用UTC时区:2019-01-24T14:01:32.258Z * mongo中的时 ...

  9. 生活中,我们不知道的……

    主题: 这些案例!触目惊心!!!女生万万小心!!!不是闹着玩的 个案1:                                           有一妇女手提包被偷,里面有手机.银行卡.钱 ...

最新文章

  1. java和c 的rsa加密算法_RSA算法签名技术Java与C++统一(加密解密结果一样)
  2. servlet增删改查实例_SpringBoot系列(2)整合MongoDB实现增删改查(完整案例)
  3. python中x=x+1的读法-python中xrange和range的区别
  4. 您试图从目录中执行CGI、ISAPI 或其他可执行程序,但该目录不允许执行程序
  5. 百度云获取外链直接下载突破限速
  6. Java: String.split(....); 结果很意外
  7. GM也坐不住了的s9t9
  8. python语言与c语言相比在分支结构上有什么不同,python 基础教程之语法篇章——一小时入门python__对比python与C语言的语法异同...
  9. 【转】XCode环境变量及路径设置 -- 待学习
  10. 比特币系列——竞争币、竞争块链和应⽤程序
  11. Prism发布了第一个版本+Entlib3.1在VS2008下工作的解决方案
  12. eclipse tomcat找不到或无法加载
  13. 2019年税收分类编码_您如何在2019年学习编码
  14. 卸载掉360之后无法删除360safe文件夹解决办法!
  15. I2C 挂死,SDA一直为低问题分析
  16. Tomcat启动失败 staring tomcat server at localhost has encoutered a problem
  17. Windows 快捷方式
  18. 越来越卷,教你使用Python实现卷积神经网络(CNN)
  19. Python 内置模块tkinter —— 秒表计时器
  20. OracleP6机场工程进度控制系列15:总进度综合管控报告

热门文章

  1. rails_Rails应用程序必备的宝石
  2. 递归计算二叉树的高度_如何使用递归方法计算二叉树的高度
  3. css一行点点点_如何通过一点点创意使CSS成为不可能
  4. freecodecamp_如何充分利用freeCodeCamp
  5. amazon alexa_亚马逊使向自定义Alexa Skills添加声音变得更加容易
  6. 小程序开发 宽度100%_这是您作为开发人员可以实现100%年度目标的方式
  7. node.js api接口_如何在Node.js API客户端中正常处理故障
  8. oracle比mysql查询快的原因_Oracle查询速度慢的原因总结
  9. ubuntu编译mysql源码
  10. docker上传镜像到仓库