聊一聊Java中的Steam流
1 引言
在我们的日常编程任务中,对于集合的制造和处理是必不可少的。当我们需要对于集合进行分组或查找的操作时,需要用迭代器对于集合进行操作,而当我们需要处理的数据量很大的时候,为了提高性能,就需要使用到并行处理,这样的处理方式是很复杂的。流可以帮助开发者节约宝贵的时间,让以上的事情变得轻松。
2 流简介
流到底是什么呢?简要的定义为“从支持数据处理操作的源生成的元素序列”,接下来对于这个定义进行简要分析。
2.1 支持数据处理操作
流的数据处理操作和数据库的可以声明式的指定分组或查找等功能支持类似,和函数式编程的思想一致,如filter、map、reduce、find、match、sort等操作,这些流操作可以串行执行,也可以并行执行。
2.2 源
流会使用一个提供数据的源,可以通过三种方式来创建对象流,一种是由集合对象创建流:
List<Integer> list = Arrays.asList(111,222,333);
Stream<Integer> stream = list.stream();
一种是由数组创建流:
IntStream stream = Arrays.stream(new int(){111,222,333});
一种是由静态方法Stream.of()创建流,底层还是Arrays.stream():
Stream<Integer> stream = Stream.of(111, 222, 333);
Stream stream = Stream.of(111, 222, 333);
从有序集合生成流时会保留原有的顺序。由列表生成的流,其元素顺序与列表一致。
还有两种特殊的流:
- 空流:Stream.empty()
- 无限流:Stream.genarate()
2.3 元素序列
流也可以和集合一样访问包含特定的元素类型的一组有序值,但是它们的主要目的不一样,集合的主要目的是在于存储和访问元素,流的主要目的在于表达计算。
3 流的思想
流式思想和生产中的流水线具有异曲同工之妙,很多流模型都会返回一个流,这些模型都只负责它所需要做的事情,并不需要格外的内存空间来存储处理的结果。这些流模型可以被链接起来形成一个大的流水线,我们在这个过程中不关注中间步骤的数据被如何处理,只需要使用整个流水线处理后的结果。接下来的代码可以体现这种思想,代码中以商品为例,我们要筛选出商品中体积大于200的前两个商品的名字。
首先是商品类的定义:
public class Goods {
private final String Name;
private final Integer Volume;
public Goods(String name, Integer volume) {
Name = name;
Volume = volume;
}
public String getName() {
return Name;
}
public Integer getVolume() {
return Volume;
}
}
接下来是商品集合的定义:
List<Goods> goods = Arrays.asList(new Goods("土豆",10),
new Goods("冰箱",900),new Goods("办公椅",300));
接下来获取我们想要的结果:
List<String> twofoods = goods.stream()//获取流
.filter(goods1 -> goods1.getVolume()>200)//筛选商品体积大于200的
.map(Goods::getName)//获取商品名称
.limit(2)//筛选头两个商品
.collect(Collectors.toList());//将结果保存在list中
这样看来,通过流来处理我们的特定需求,是不是比使用集合的迭代要方便很多呢?
4 流处理的特性
- 不存储数据
- 不会改变数据源
- 只可被使用一次
这里我们使用一个测试类StreamCharacteristic来验证流处理的以上特性:
import org.springframework.util.Assert;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamCharacteristic {
public void test1(){
List<Integer> list = Arrays.asList(1,2,2,5,6,9);
list.stream().distinct();
System.out.println(list.size());
}
public void test2(){
List<String> list = Arrays.asList("wms", "KA", "5.0");
Stream<String> stream = list.stream();
stream.forEach(System.out::println);
stream.forEach(System.out::println);
}
}
test1()中的结果为6,尽管我们对于list对象所生成的Stream流做了去重操作distinct(),但是不影响数据源list。
test2()中调用了两次 stream.forEach方法来打印每一个单词,第二次调用时,抛出了一个“java.lang.IllegalStateException”异常:“stream has already been operated upon or closed”。这说明流不存储数据,遍历完后这个流已经被消费掉了,而且流不可以重复使用。
5 流操作与流的使用
将所有的流操作连接起来可以组合成一个管道,管道有两类操作:中间操作和终端操作。
StreamAPI常用的中间操作有:filter,map,limit,sorted,distinct。
StreamAPI常用的终端操作有:forEach,count,collect。
在使用流的时候,主要需要三个要素:一个用来执行查询的数据源,用来形成一条流的流水线的中间操作链,一个能够执行流水线并能生成结果的终端操作。
下图展示了流的整个操作流程:
6 总结
- 流是从支持数据处理操作的源生成的元素序列
- 流的思想类似于生产中的流水线
- 流不存储数据,不改变数据源,只能被改变一次
- 流的操作主要分为中间操作和终端操作两大类
作者:京东物流 王辰玮
来源:京东云开发者社区 自猿其说Tech
聊一聊Java中的Steam流的更多相关文章
- java中的IO流
Java中的IO流 在之前的时候我已经接触过C#中的IO流,也就是说集中数据固化的方式之一,那么我们今天来说一下java中的IO流. 首先,我们学习IO流就是要对文件或目录进行一系列的操作,那么怎样操 ...
- java中的缓冲流BufferedWriter和BufferedReader
java中的缓冲流有BufferedWriter和BufferedReader 在java api 手册中这样说缓冲流: 从字符输入流中读取文本,缓冲各个字符,从而实现字符.数组和行的高效读取.可以指 ...
- java 中 “文件” 和 “流” 的简单分析
java 中 FIle 和 流的简单分析 File类 简单File 常用方法 创建一个File 对象,检验文件是否存在,若不存在就创建,然后对File的类的这部分操作进行演示,如文件的名称.大小等 / ...
- Java中的IO流总结
Java中的IO流总结 1. 流的继承关系,以及字节流和字符流. 2. 节点流FileOutputStream和FileInputStream和处理流BufferedInputStream和Buffe ...
- Java中的IO流大体介绍
由于Java中的IO流是在是知识点繁多,所以我大约花了1周的时间将其整理起来.但是整理起来后并不是将完事了,我还是要分字节流和字符流来讲述.然后字节流和字符流中还有是否带有缓冲流. 讲述完IO流后我将 ...
- Java中的IO流,Input和Output的用法,字节流和字符流的区别
Java中的IO流:就是内存与设备之间的输入和输出操作就成为IO操作,也就是IO流.内存中的数据持久化到设备上-------->输出(Output).把 硬盘上的数据读取到内存中,这种操作 成为 ...
- Java中的IO流(五)
上一篇<Java中的IO流(四)>记录了一下Properties类,此类不属于IO流,它属于集合框架.接下来说一下IO流中的其它流 一,打印流PrintStream PrintStream ...
- Java中的IO流(六)
上一篇<Java中的IO流(五)>把流中的打印流PrintStream,PrintWriter,序列流SequenceInputStream以及结合之前所记录的知识点完成了文件的切割与文件 ...
- JAVA 中的IO流
Java中的IO流是用来处理设备与设备之前的数据传输,在java中以流的形式传输.流分为两类:字节流和字符流. 字节流:InputStream,OutPutSteam.(计算机内的数据都是以字节存储的 ...
- Java中的IO流(四)
上一篇<Java中的IO流(三)>把IO流中的文件及目录操作的对象File类记录了一下,本篇把本不属性IO流但又和IO流有关系的一个对象作一下记录,此对象本属于集合框架里的一个子集,即Pr ...
随机推荐
- 碉堡!“万物皆可分”标记模型上线「GitHub 热点速览」
这周有个让人眼前一亮的图像识别模型 segment-anything,它能精细地框出所有可见物体,它标记出的物体边界线清晰可见.如此出色的模型,自然获得了不少人的赞赏,开源没几天,就拿下了 18k+ ...
- layUI之树状表格异步加载组件treetableAsync.js(基于treetable.js)
目录 概述 1. 使用说明 2. 使用需知 2.1 本组件依赖于treetable.js[重中之重] 2.2 本组件基于layUIAdmin进行使用 2.3 本组件的方法支持treetable.js的 ...
- 【深度思考】聊聊JDK动态代理原理
1. 示例 首先,定义一个接口: public interface Staff { void work(); } 然后,新增一个类并实现上面的接口: public class Coder implem ...
- MD5简述及常见解密网址推荐
什么是md5 MD5(Message-Digest Algorithm 5)(信息-摘要算法5), 一种被广泛使用的[密码散列函数](https://baike.baidu.com/item/密码散列 ...
- CSS绘制虚线的方案
一.实现效果 二.代码实现 <div class="line"></div> .line { width: 1px; /* 虚线宽度 */ backgrou ...
- 音视频八股文(9)-- flv的h264六层结构和aac六层结构
flv介绍 FLV(Flash Video)是Adobe公司推出的⼀种流媒体格式,由于其封装后的⾳视频⽂件体积⼩.封装简单等特点,⾮常适合于互联⽹上使⽤.⽬前主流的视频⽹站基本都⽀持FLV.采⽤FLV ...
- 2022-06-28:以下golang代码输出什么?A:true;B:false;C:panic;D:编译失败。 package main import “fmt“ func main() {
2022-06-28:以下golang代码输出什么?A:true:B:false:C:panic:D:编译失败. package main import "fmt" func ma ...
- 2021-05-04:给定一个非负整数c,你要判断是否存在两个整数a和b,使得a*a+b*b=c。【举例】c=5时,返回true。c=4时,返回true。c=3时,返回false。
2021-05-04:给定一个非负整数c,你要判断是否存在两个整数a和b,使得aa+bb=c.[举例]c=5时,返回true.c=4时,返回true.c=3时,返回false. 福大大 答案2021- ...
- 基于go语言的声明式流式ETL,高性能和弹性流处理器
简要介绍Benthos,并给出若干示例,指导如何安装和运行. Benthos Benthos 是一个开源的.高性能和弹性的数据流处理器,能够以各种代理模式连接各种源和汇,可以帮助用户在不同的消息流之间 ...
- pages.json 文件:pages 节点
pages uni-app 通过 pages 节点配置应用由哪些页面组成,pages 节点接收一个数组,数组每个项都是一个对象,其属性值如下: 属性 类型 默认值 描述 path String 配 ...