半年前开始试着使用Java的新特性,给我印象最深的就是Stream流和Optional。其中Stream提高了看法效率,让代码看起来十分清爽。

为什么要使用流?

摘要中已经说明了,为了提高开发效率。流可以帮助我们高效操作集合,流帮助我们通过流水线的方式对集合进行删减合并排序修改,并最终返回我们想要的元素数据或统计数据。流水线的意思是说,一批元素不需要等待全部元素都完成某步操作,才进行下步操作,而是可以尽早进行下步操作,就好像流水线工厂一样,这为流高效运作提供了基础。流还有一个内部迭代的概念,就是把for循环显示迭代隐藏起来了,这样可以更方便的并行开发

流的使用

准备

在使用流之前需要做些准备,首先说明两个概念:中间操作终端操作中间操作就好比生产车间的一步一步元素处理,每步处理之后,里面的元素样式或者数据结构可能发生改变了,但是它还是流。终端操作就好比产品生产完了,要打包装箱,变成最终消费者可见的最终形态,此时,它已经是产品,不再是流了。

接着为了演示操作,先模拟几条数据

List<JSONObject> menu = new ArrayList<>();
menu.add(new JSONObject().putOpt("name","宫保鸡丁").putOpt("price","28"));
menu.add(new JSONObject().putOpt("name","鱼香肉丝").putOpt("price","30"));
menu.add(new JSONObject().putOpt("name","肉夹馍").putOpt("price","6"));
menu.add(new JSONObject().putOpt("name","煎饼").putOpt("price","6"));

常用的中间操作

filter

filter应该是Stream操作里面最常见的了,过滤器顾名思义就是过滤数据用的,filter的参数可以是lambda表达式。

//比如下面这句话,就是得到所有价格小于10的食物,得到的还是流。
//stream()方法将集合转成流
menu.stream().filter(jsonObject -> jsonObject.getInt("price")<10);

distinct 、 limit 和 skip

distinct是去重,limit是截取前几个元素,skip是跳过前多少个元素。

List<Integer> integerList = new ArrayList<>();
integerList.add(1);
integerList.add(1);
integerList.add(2);
integerList.add(3);
integerList.stream()
.distinct()//经过去重,流还剩1、2、3
.skip(1)//跳过第一个元素,流中还有2、3
.limit(1);//截取第一个元素,流中还剩2

map

map映射,上面的filter是将元素筛选,map则是改变元素的样式。比如,我们想要知道所有小于10块食物的名字。

menu.stream()
.filter(jsonObject -> jsonObject.getInt("price")<10)//此时还是jsonObject
.map(jsonObject -> jsonObject.getStr("name"));//此时变成了String

flatMap

流的合并,可以将多个数组合并操作,这样返回元素不是流,而是具体元素本身了。

Stream.of(menu,foreignMenu)//此时元素是流 List<Stream>
.flatMap(x -> x.stream())//此时元素是jsonObject List<jsonObject>
.map(jsonObject -> jsonObject.getStr("name"))
.distinct();

常用的终端方法

allMatch、anyMatch、noneMatch、findFirst和findAny

方法 含义
allMatch 检查谓词是否匹配所有元素
anyMatch 检查谓词是否至少匹配一个元素
noneMatch 确保流中没有任何元素与给定的谓词匹配
findFirst 查找第一个符合条件的元素
findAny 将返回当前流中的任意元素
//前三个方法都是返回boolean类型
boolean allMatchBool = menu.stream()
.allMatch(jsonObject -> jsonObject.getInt("price") < 10);
boolean noneMatchBool = menu.stream()
.noneMatch(jsonObject -> jsonObject.getInt("price") < 10);
boolean anyMatchBool = menu.stream()
.anyMatch(jsonObject -> jsonObject.getInt("price") < 10);

上面个方法返回的都是boolean类型,findFirst、findAny返回的都是元素。

//关于Optional,先不关心,总之是元素就对了
Optional<JSONObject> first = menu.stream().findFirst();
Optional<JSONObject> any = menu.stream().findAny(); System.out.println(first.get().toString());
System.out.println(any.get().toString()); //输出
//{"price":"28","name":"宫保鸡丁"}
//{"price":"28","name":"宫保鸡丁"}

以上两个方法,只要找到符合条件的数据,流就提前结束了。为什么都是输出第一个元素,却要实现有两个方法呢?因为并行,findAny在并行方面限制会少一些。

reduce

最开始的时候说了,最终的返回值可以是元素集合,也可以是统计数据(或者说归纳),比如说元素求和。假设我们需要menu中所有食品各要一份需要花多少钱。

Optional<Integer> price = menu.stream()//List<JsonObject>
.map(jsonObject -> jsonObject.getInt("price"))//先将元素转成数字List<Integer>
.reduce((x, y) -> x + y);
System.out.println(price.get());

max和min

这个好理解,就是最大值和最小值嘛。效果类似于

.reduce(Integer::max)
.reduce(Integer::min)

常用流汇总

其中没有展示sorted、count这个都好理解。至于collect这个后面讲,用的比较多。

流的转化

除了对象流(Stream)以外,还有一些类型流,比如说 IntStream(以 IntStream 举例,其他类似)上面求和返回的是Optional对象,那可以直接返回Integer类型吗?

//使用映射方法mapToInt()就ok了
int price = menu.stream()//Stream
.mapToInt(jsonObject -> jsonObject.getInt("price"))//IntStream
.sum();
//类型流转化回对象流,可以使用boxed()
IntStream intStream = menu.stream()
.mapToInt(jsonObject -> jsonObject.getInt("price"));
Stream<Integer> boxed = intStream.boxed();
//当然了IntStream中有很多int类型操作的方法,就不一一举例了,源码打开一看,见名知意

收集器

前面讲的常用的中间操作,返回值都是流,还有一些中断操作,返回值都是Optional或者数值。可别忘了Stream最开始的初衷是为了解决集合操作问题。最终转化成集合使用的中断操作collect,参数是接口 Collector,里面有众多转化方法。

转换成集合

最常用的莫非toList() 这个方法了,将返回结果变成List。

List<JSONObject> list = menu.stream()
.filter(jsonObject -> jsonObject.getInt("price") < 10)
.collect(Collectors.toList());
//当然还有toSet()等等,触类旁通

字符串拼接

比较常用,就是字符串链接了。使用joining()方法

String s = menu.stream()
.filter(jsonObject -> jsonObject.getInt("price") < 10)
.map(jsonObject -> jsonObject.getStr("name"))
.collect(Collectors.joining(","));

分组

根据提供的属性分组,使用 groupingBy() ,为了方便说明,给上面各种食品一个type值:

List<JSONObject> menu = new ArrayList<>();
menu.add(new JSONObject().putOpt("name","宫保鸡丁").putOpt("price","28").putOpt("type","good"));
menu.add(new JSONObject().putOpt("name","鱼香肉丝").putOpt("price","30").putOpt("type","good"));
menu.add(new JSONObject().putOpt("name","肉夹馍").putOpt("price","6").putOpt("type","normal"));
menu.add(new JSONObject().putOpt("name","煎饼").putOpt("price","6").putOpt("type","normal")); Map<String, List<JSONObject>> type = menu.stream()
.collect(Collectors.groupingBy(jsonObject -> jsonObject.getStr("type")));
System.out.println(type);
//输出
//{normal=[{"price":"6","name":"肉夹馍","type":"normal"}, {"price":"6","name":"煎饼","type":"normal"}], good=[{"price":"28","name":"宫保鸡丁","type":"good"}, {"price":"30","name":"鱼香肉丝","type":"good"}]}

与分组类似的还有一个方法 partitioningBy (),分区,不过它的参数位于是boolean类型。

再来看看Java的新特性——Stream流的更多相关文章

  1. 这可能是史上最好的 Java8 新特性 Stream 流教程

    本文翻译自 https://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/ 作者: @Winterbe 欢迎关注个人微信公众 ...

  2. Java 8 新特性-Stream更优雅的处理集合入门

    Java 8 新特性之--Stream 一. 简单介绍 Stream是Java 8提出了的一种新的对集合对象功能的增强.它集合Lambda表达式,对集合提供了一些非常便利,高效的操作,使得代码具有非常 ...

  3. Java8新特性 Stream流式思想(一)

    遍历及过滤集合中的元素使用传统方式遍历及过滤集合中的元素package cn.com.zq.demo01.Stream.test01.Stream; import java.util.ArrayLis ...

  4. Java1.8新特性 - Stream流式算法

    一. 流式处理简介   在我接触到java8流式数据处理的时候,我的第一感觉是流式处理让集合操作变得简洁了许多,通常我们需要多行代码才能完成的操作,借助于流式处理可以在一行中实现.比如我们希望对一个包 ...

  5. Java8新特性 Stream流式思想(二)

    如何获取Stream流刚开始写博客,有一些不到位的地方,还请各位论坛大佬见谅,谢谢! package cn.com.zq.demo01.Stream.test01.Stream; import org ...

  6. 再来看看Java的新特性——其他新特性

    关于剩余Java8新特性知识点总结,包含:默认方法.Optional.CompletableFuture.时间相关. 默认方法 默认方法皆在帮助Java新功能可以兼容低版本JDK已开发的程序. 比如说 ...

  7. java8 新特性Stream流的应用

    作为一个合格的程序员,如何让代码更简洁明了,提升编码速度尼. 今天跟着我一起来学习下java 8  stream 流的应用吧. 废话不多说,直入正题. 考虑以下业务场景,有四个人员信息,我们需要根据性 ...

  8. Java8新特性 Stream流式思想(三)

    Stream接口中的常用方法 forEach()方法package cn.com.cqucc.demo02.StreamMethods.Test02.StreamMethods; import jav ...

  9. JDK8新特性---stream流

    项目上用到了stream流,找篇blog,转载一下,介绍下Stream流的用法. 1 流概述  流是 JDK8 新增的成员,允许以声明性方式处理数据集合,可以把 Stream 流看作是遍历数据集合的一 ...

随机推荐

  1. java题求代码,4、现在有如下的一个数组: int oldArr[]={1,3,4,5,0,0,6,6,0,5,4,7,6,7,0,5} 要求将以上数组中值为0的项去掉,将不为0的值存入一个新的数组,生成的新数组为: int newArr[]={1,3,4,5,6,6,5,4,7,6,7,5}

    public class TEST { public static void main(String[] args) { int [] oldArr= {1,3,4,5,0,0,6,6,0,5,4,7 ...

  2. JS隔行换色和全选的实现

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. 「黑科技」智能消毒防疫机器人 技术方案介绍-disinfection robot

    消毒机器人 小新防疫消杀机器人 - 自主导航全方位360°臭氧杀菌消毒机器人,采用臭氧无阻碍.无死角.遍布整个空间除菌:强力涡轮风机,30㎡室内空气循环6次/h,10分钟速效杀菌.除异味.自动转化为氧 ...

  4. 关于Oracle中job定时器(通过create_job创建的)配置示例

    begin dbms_scheduler.create_job(job_name => 'JOB_BASIC_STATISTIC', job_type => 'STORED_PROCEDU ...

  5. JS-语句四

    For 循环: for 循环是创建循环时常会用到的工具. 下面是 for 循环的语法: ; 语句 ; 语句 ) { 被执行的代码 } 其中语句1是初始值:语句2是.条件判断:语句3是状态改变:被执行的 ...

  6. Python调用OpenCV读显写

    OpenCV提供了python的接口,而且很重要的一点是python下的很多接口名与C++的接口名是一样的,这一篇先记录python调用OpenCV去读取图像.显示图像和保存图像. 1.OpenCV读 ...

  7. OpenStack(四)——使用Kolla部署OpenStack多节点云

    (1).实验环境 主机名 IP地址 角色 内存 网卡 CPU 磁盘 OpenStack-con 192.168.128.110 controller(控制) 8G 桥接网卡ens32和ens33 4核 ...

  8. CI中site_url()和base_url()的区别

    CI中site_url()和base_url()的区别 来源:未知    时间:2014-10-20 11:38   阅读数:150   作者:xbdadmin [导读] 在使用CI框架的使用经常碰到 ...

  9. Spring DATA Neo4J(一)

    Spring DATA Neo4J——简介 Spring Framework提供了一下模块来处理基于Java的应用程序的DAO层 Spring JDBC Spring ORM Spring DATA ...

  10. Excel Old format or invalid type library 错误原因

    Old format or invalid type library 错误原因 调用excel方法失败,Old format or invalid type library 解决方案: 1,这是Exc ...