Stream闪亮登场
Stream闪亮登场
一. Stream(流)是什么,干什么
Stream是一类用于替代对集合操作的工具类+Lambda式编程,他可以替代现有的遍历、过滤、求和、求最值、排序、转换等
二. Stream操作方式
- 并行方式parallelStream
- 顺序方式Stream
三. Stream优势
- Lambda 可有效减少冗余代码,减少开发工作量
- 内置对集合List、Map的多种操作方式,含基本数据类型处理
- 并行Stream有效率优势(内置多线程)
四. Stream(流)的基本使用
- 遍历forEach
@Test
public void stream() {
//操作List
List<Map<String, String>> mapList = new ArrayList() {
{
Map<String, String> m = new HashMap();
m.put("a", "1");
Map<String, String> m2 = new HashMap();
m2.put("b", "2");
add(m);
add(m2);
}
};
mapList.stream().forEach(item-> System.out.println(item));
//操作Map
Map<String,Object> mp = new HashMap(){
{
put("a","1");
put("b","2");
put("c","3");
put("d","4");
}
};
mp.keySet().stream().forEachOrdered(item-> System.out.println(mp.get(item)));
}
- 过滤filter
List<Integer> mapList = new ArrayList() {
{
add(1);
add(10);
add(12);
add(33);
add(99);
}
};
//mapList.stream().forEach(item-> System.out.println(item));
mapList = mapList.stream().filter(item->{
return item>30;
}).collect(Collectors.toList());
System.out.println(mapList);
- 转换map和极值
@Test
public void trans(){
List<Person> ps = new ArrayList<Person>(){
{
Person p1 = new Person();
p1.setAge(11);
p1.setName("张强"); Person p2 = new Person();
p2.setAge(17);
p2.setName("李思"); Person p3 = new Person();
p3.setAge(20);
p3.setName("John"); add(p1);
add(p2);
add(p3);
}
};
//取出所有age字段为一个List
List<Integer> sumAge = ps.stream().map(Person::getAge).collect(Collectors.toList());
System.out.println(sumAge);
//取出age最大的那
Integer maxAge =sumAge.stream().max(Integer::compare).get();
System.out.println(maxAge);
} class Person{ private String name;
private Integer age; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
}
}
#### 五. Stream(流)的效率
+ 模拟非耗时简单业务逻辑
class Person{
private String name;
private int age;
private Date joinDate;
private String label;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Date getJoinDate() {
return joinDate;
}
public void setJoinDate(Date joinDate) {
this.joinDate = joinDate;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public class DataLoopTest {
private static final Logger LOG= LoggerFactory.getLogger(DataLoopTest.class);
private static final List<Person> persons = new ArrayList<>();
static {
for(int i=0;i<=1000000;i++){
Person p = new Person();
p.setAge(i);
p.setName("zhangSan");
p.setJoinDate(new Date());
persons.add(p);
}
}
/**
* for 循环耗时 ===> 1.988
* for 循环耗时 ===> 2.198
* for 循环耗时 ===> 1.978
*
*/
@Test
public void forTest(){
Instant date_start = Instant.now();
int personSize = persons.size();
for(int i=0;i<personSize;i++){
persons.get(i).setLabel(persons.get(i).getName().concat("-"+persons.get(i).getAge()).concat("-"+persons.get(i).getJoinDate().getTime()));
}
Instant date_end = Instant.now();
LOG.info("for 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0);
}
/**
* forEach 循环耗时 ===> 1.607
* forEach 循环耗时 ===> 2.242
* forEach 循环耗时 ===> 1.875
*/
@Test
public void forEach(){
Instant date_start = Instant.now();
for(Person p:persons){
p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));
}
Instant date_end = Instant.now();
LOG.info("forEach 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0);
}
/**
* streamForeach 循环耗时 ===> 1.972
* streamForeach 循环耗时 ===> 1.969
* streamForeach 循环耗时 ===> 2.125
*/
@Test
public void streamForeach(){
Instant date_start = Instant.now();
persons.stream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));
Instant date_end = Instant.now();
LOG.info("streamForeach 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0);
}
/**
* parallelStreamForeach 循环耗时 ===> 1.897
* parallelStreamForeach 循环耗时 ===> 1.942
* parallelStreamForeach 循环耗时 ===> 1.642
*/
@Test
public void parallelStreamForeach(){
Instant date_start = Instant.now();
persons.parallelStream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));
Instant date_end = Instant.now();
LOG.info("parallelStreamForeach 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0);
}
}
+ 模拟耗时简单业务逻辑
public class DataLoopBlockTest {
private static final Logger LOG= LoggerFactory.getLogger(DataLoopTest.class);
private static final List<Person> persons = new ArrayList<>();
static {
for(int i=0;i<=100000;i++){
Person p = new Person();
p.setAge(i);
p.setName("zhangSan");
p.setJoinDate(new Date());
persons.add(p);
}
}
/**
* for 循环耗时 ===> 101.385
* for 循环耗时 ===> 102.161
* for 循环耗时 ===> 101.472
*
*/
@Test
public void forTest(){
Instant date_start = Instant.now();
int personSize = persons.size();
for(int i=0;i<personSize;i++){
try {
Thread.sleep(1);
persons.get(i).setLabel(persons.get(i).getName().concat("-"+persons.get(i).getAge()).concat("-"+persons.get(i).getJoinDate().getTime()));
}catch (Exception e){
e.printStackTrace();
}
}
Instant date_end = Instant.now();
LOG.info("for 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0);
}
/**
* forEach 循环耗时 ===> 101.027
* forEach 循环耗时 ===> 102.488
* forEach 循环耗时 ===> 101.608
*/
@Test
public void forEach(){
Instant date_start = Instant.now();
for(Person p:persons){
try {
Thread.sleep(1);
p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));
}catch (Exception e){
e.printStackTrace();
}
}
Instant date_end = Instant.now();
LOG.info("forEach 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0);
}
/**
* streamForeach 循环耗时 ===> 103.246
* streamForeach 循环耗时 ===> 101.128
* streamForeach 循环耗时 ===> 102.615
*/
@Test
public void streamForeach(){
Instant date_start = Instant.now();
//persons.stream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));
persons.stream().forEach(p->{
try {
Thread.sleep(1);
p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));
}catch (Exception e){
e.printStackTrace();
}
});
Instant date_end = Instant.now();
LOG.info("streamForeach 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0);
}
/**
* parallelStreamForeach 循环耗时 ===> 51.391
* parallelStreamForeach 循环耗时 ===> 53.509
* parallelStreamForeach 循环耗时 ===> 50.831
*/
@Test
public void parallelStreamForeach(){
Instant date_start = Instant.now();
//persons.parallelStream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));
persons.parallelStream().forEach(p->{
try {
Thread.sleep(1);
p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));
}catch (Exception e){
e.printStackTrace();
}
});
Instant date_end = Instant.now();
LOG.info("parallelStreamForeach 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0);
//LOG.info("\r\n===> {}",JSON.toJSONString(persons.get(10000)));
}
}
可以看到在百万数据下做简单数据循环处理,对于普通for(for\foreach)循环或stream(并行、非并行)下,几者的效率差异并不明显,
注意: 在百万数据下,普通for、foreach循环处理可能比stream的方式快许多,对于这点效率的损耗,其实lambda表达式对代码的简化更大!
另外,在并行流的循环下速度提升了一倍之多,当单个循环耗时较多时,会拉大与前几者的循环效率
(以上测试仅对于循环而言,其他类型业务处理,比如排序、求和、最大值等未做测试,个人猜测与以上测试结果相似)
#### 六. Stream(流)注意项
+ 并行stream不是线程安全的,当对循坏外部统一对象进行读写时候会造成意想不到的错误,这需要留意
+ 因stream总是惰性的,原对象是不可以被修改的,在集合处理完成后需要将处理结果放入一个新的集合容器内
+ 普通循环与stream(非并行)循环,在处理处理数据量比较大的时候效率是一致的,推荐使用stream的形式
+ 对于List删除操作,目前只提供了removeIf方法来实现,并不能使用并行方式
+ 对于lambda表达式的写法
- 当表达式内只有一个返回boolean类型的语句时候语句是可以简写的,例如:
persons.parallelStream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));
- 当表达式内会有一些复杂处理逻辑时需要加上大括号,这与初始化List参数方式大致一致
persons.parallelStream().forEach(p->{
try {
Thread.sleep(1);
p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));
}catch (Exception e){
e.printStackTrace();
}
});
#### 七. stream&Lambda表达式常用api方法
+ 流到流之间的转换类
- filter(过滤)
- map(映射转换)
- mapTo[Int|Long|Double] (到基本类型流的转换)
- flatMap(流展开合并)
- flatMapTo[Int|Long|Double]
- sorted(排序)
- distinct(不重复值)
- peek(执行某种操作,流不变,可用于调试)
- limit(限制到指定元素数量)
- skip(跳过若干元素)
+ 流到终值的转换类
- toArray(转为数组)
- reduce(推导结果)
- collect(聚合结果)
- min(最小值)
- max(最大值)
- count (元素个数)
- anyMatch (任一匹配)
- allMatch(所有都匹配)
- noneMatch(一个都不匹配)
- findFirst(选择首元素)
- findAny(任选一元素)
+ 直接遍历类
- forEach (不保证顺序遍历,比如并行流)
- forEachOrdered(顺序遍历)
+ 构造流类
- empty (构造空流)
- of (单个元素的流及多元素顺序流)
- iterate (无限长度的有序顺序流)
- generate (将数据提供器转换成无限非有序的顺序流)
- concat (流的连接)
- Builder (用于构造流的Builder对象)
Stream闪亮登场的更多相关文章
- JAVA版本微信管家平台—JeeWx 捷微 4.1 微服务版本发布,微信砍价活动闪亮登场!
捷微 4.1 微服务版本发布,微信砍价活动闪亮登场 ^_^ JEEWX 从4.0版本开始,技术架构全新换代更名 “捷微H5”.这是一款开源免费的微信运营平台,是jeewx的新一代产品,平台涵盖了: ...
- [转帖]YES!AMD千元无敌U闪亮登场、16核至尊为用户着想
YES!AMD千元无敌U闪亮登场.16核至尊为用户着想 投递人 itwriter 发布于 2019-09-30 09:34 评论(0) 有567人阅读 原文链接 [收藏] « » https://ne ...
- 6.24 AppCan移动开发者大会,我爱我家即将闪亮登场!
6.24 AppCan移动开发者大会进入倒计时,报名通道即将关闭! “6月24日, 2016AppCan移动开发者大会即将召开,以“平台之上,应用无限”为主题,1500位行业精英汇聚在此,重磅新品发布 ...
- LayIM.AspNetCore Middleware 开发日记(七)Asp.Net.Core.SignalR闪亮登场
前言 前几篇介绍了整个中间件的构成,路由,基本配置等等.基本上没有涉及到通讯部分.不过已经实现了融云的通讯功能,由于是第三方的就不在单独去写.正好.NET Core SignalR已经出来好久了, ...
- 七种武器:JavaScript 新特性闪亮登场
JavaScript(或ECMA Script) 是一门不断发展的语言,有许多关于如何前进的建议和想法.TC39(技术委员会39)是负责定义JS标准和特性的委员会,今年他们非常活跃.以下是目前处于&q ...
- 浏览器小程序(Browser Applet)闪亮登场
2017 年 1 月 9 日,微信小程序横空出世.随后,支付宝小程序.今日头条小程序.百度智能小程序.360小程序等纷纷推出,自此国内软件功能扩展领域进入到了小程序时代,小程序为丰富其宿主软件的功能和 ...
- 京东 Vue3 组件库闪亮登场
京东零售开源项目 NutUI 是一套京东风格的轻量级移动端 Vue 组件库,是开发和服务于移动 Web 界面的企业级产品.经过长时间的开发与打磨,NutUI 3.0 终于要和大家见面了!3.0 版本在 ...
- .net Stream篇(六)
BufferedStream 目录: 简单介绍一下BufferedStream 如何理解缓冲区? BufferedStream的优势 从BufferedStream 中学习装饰模式 如何理解装饰模式 ...
- 【Stream—6】BufferedStream相关知识分享
一.简单介绍以下BufferedStream 在前几章的讲述中,我们已经能够掌握流的基本特性和特点,一般进行对流的处理时,系统肩负着IO所带来的开销,调用十分频繁,这时候就应该想个办法减少这种开销,而 ...
随机推荐
- HttpUtility.UrlEncode()关于空格的编码问题
因为 HttpUtility.UrlEncode 在 Encode 的时候, 将空格转换成加号"+", 在 Decode 的时候将"+"号转为空格, 但是浏览器 ...
- imageview设置图片时超长超大图片超出限制(OpenGLRenderer: Bitmap too large to be uploaded into a texture (996x9116, max=4096x4096))
问题:遇到超长图片,宽长等比缩放,比如宽度同屏幕同宽,长度等比放大,放到后遇到长度超出OpenGLRenderer的最大限制,导致图片无法显示出来: 解决办法: //图片超出GPU对于openglRe ...
- mac 终端里进入mysql和退出
先在偏好设置里启动mysql服务 获取超级权限 在终端输入代码 sudo su 输入完后获取超级权限 终端显示 sh-3.2# 输入本机密码(Apple ID密码) 接着通过绝对路径登陆 代码 /us ...
- 微信小程序的桌面图标问题
提问: 笔者在发布小程序后,发现无法在安卓手机创建桌面图标,而其它的小程序却可以. 回答: 在小程序后台页面(从公众平台进入)完整填写小程序的信息,之后便可创建桌面图标. 这可能是微信的某种筛查机制在 ...
- 云栖社区用机器人爬CSDN的文章?
这个云栖社区的文章https://yq.aliyun.com/ziliao/539322 这篇文章是我13年写的,不知道咋插入图片,见谅. 下面是我的文件记录 分享XAML图标的网站 原创 2013年 ...
- VUE 滚动插件(better-scroll)
1. 概述 1.1 说明 better-scroll是一款重点解决移动端(已支持PC)各种滚动场景需求的插件.例如淘宝聚划算中的类型选择(女装/家纺/生鲜美食等),没有滚动条显示却实现了滚动功能. 1 ...
- cadcam
Email:kefu007@vip.qq.com 13D TIMON 2007 英語版2007 23DVIA Composer V6R2013 中文版2013 3ABQUS V6.11 6.11 4A ...
- oracle查询某张表的外键,并用 truncate 命令有外键的表中的数据
注:本文来源于<oracle查询某张表的外键(最终解决办法)> 一:几个查询表外键的脚本 select b.table_name, b.column_name from user_cons ...
- LoadRunner学习笔记(二)
LoadRunner Controller简介: 当虚拟用户脚本开发完成后,使用controller将这个执行脚本的用户从单用户转化为多用户,从而,模拟大量用户操作, 进而形成负债(多用户单循环,多用 ...
- 小米众筹新品---8H凉感慢回弹记忆绵枕 99元 上手开箱图
在众目睽睽之下,商城终于成了杂货铺 众筹发布了第98期新品——8H凉感慢回弹记忆绵枕H1,售价为99元,主打舒适凉感,抗菌吸湿,三曲线护颈设计,3~5秒慢回弹. 本着程序员的读书历程:x 语言入门 — ...