我们期待了很久lambda为java带来闭包的概念,但是如果我们不在集合中使用它的话,就损失了很大价值。现有接口迁移成为lambda风格的问题已经通过default methods解决了,在这篇文章将深入解析Java集合里面的批量数据操作(bulk operation),解开lambda最强作用的神秘面纱。

1.关于JSR335

JSR是Java Specification Requests的缩写,意思是Java 规范请求,Java 8 版本的主要改进是 Lambda 项目(JSR 335),其目的是使 Java 更易于为多核处理器编写代码。JSR 335=lambda表达式+接口改进(默认方法)+批量数据操作。加上前面两篇,我们已是完整的学习了JSR335的相关内容了。

2.外部VS内部迭代

以前Java集合是不能够表达内部迭代的,而只提供了一种外部迭代的方式,也就是for或者while循环。

List persons = asList(new Person("Joe"), new Person("Jim"), new Person("John"));
for (Person p :  persons) {p.setLastName("Doe");
}

上面的例子是我们以前的做法,也就是所谓的外部迭代,循环是固定的顺序循环。在现在多核的时代,如果我们想并行循环,不得不修改以上代码。效率能有多大提升还说定,且会带来一定的风险(线程安全问题等等)。 
要描述内部迭代,我们需要用到Lambda这样的类库,下面利用lambda和Collection.forEach重写上面的循环

persons.forEach(p->p.setLastName("Doe"));

现在是由jdk 库来控制循环了,我们不需要关心last name是怎么被设置到每一个person对象里面去的,库可以根据运行环境来决定怎么做,并行,乱序或者懒加载方式。这就是内部迭代,客户端将行为p.setLastName当做数据传入api里面。

内部迭代其实和集合的批量操作并没有密切的联系,借助它我们感受到语法表达上的变化。真正有意思的和批量操作相关的是新的流(stream)API。新的java.util.stream包已经添加进JDK 8了。

3.Stream API

流(Stream)仅仅代表着数据流,并没有数据结构,所以他遍历完一次之后便再也无法遍历(这点在编程时候需要注意,不像Collection,遍历多少次里面都还有数据),它的来源可以是Collection、array、io等等。

3.1中间与终点方法

流作用是提供了一种操作大数据接口,让数据操作更容易和更快。它具有过滤、映射以及减少遍历数等方法,这些方法分两种:中间方法终端方法,“流”抽象天生就该是持续的,中间方法永远返回的是Stream,因此如果我们要获取最终结果的话,必须使用终点操作才能收集流产生的最终结果。区分这两个方法是看他的返回值,如果是Stream则是中间方法,否则是终点方法。具体请参照Stream的api。

简单介绍下几个中间方法(filter、map)以及终点方法(collect、sum)

3.1.1Filter

在数据流中实现过滤功能是首先我们可以想到的最自然的操作了。Stream接口暴露了一个filter方法,它可以接受表示操作的Predicate(断言)实现来使用定义了过滤条件的lambda表达式。

List persons = …
Stream personsOver18 = persons.stream().filter(p -> p.getAge() > 18);//过滤18岁以上的人

3.1.2Map

假使我们现在过滤了一些数据,比如转换对象的时候。Map操作允许我们执行一个Function的实现(Function<T,R>的泛型T,R分别表示执行输入和执行结果),它接受入参并返回。首先,让我们来看看怎样以匿名内部类的方式来描述它

Stream adult= persons.stream().filter(p -> p.getAge() > 18).map(new Function() {@Overridepublic Adult apply(Person person) {return new Adult(person);//将大于18岁的人转为成年人
                  }});

现在,把上述例子转换成使用lambda表达式的写法:

Stream map = persons.stream().filter(p -> p.getAge() > 18).map(person -> new Adult(person));

3.1.3Count

count方法是一个流的终点方法,可使流的结果最终统计,返回int,比如我们计算一下满足18岁的总人数

int countOfAdult=persons.stream().filter(p -> p.getAge() > 18).map(person -> new Adult(person)).count();

3.1.4Collect

collect方法也是一个流的终点方法,可收集最终的结果

List adultList= persons.stream().filter(p -> p.getAge() > 18).map(person -> new Adult(person)).collect(Collectors.toList());

或者,如果我们想使用特定的实现类来收集结果:

List adultList = persons.stream().filter(p -> p.getAge() > 18).map(person -> new Adult(person)).collect(Collectors.toCollection(ArrayList::new));

篇幅有限,其他的中间方法和终点方法就不一一介绍了,看了上面几个例子,大家明白这两种方法的区别即可,后面可根据需求来决定使用。

3.2顺序流与并行流

每个Stream都有两种模式:顺序执行和并行执行。
顺序流:

List <Person> people = list.getStream.collect(Collectors.toList());

并行流:

List <Person> people = list.getStream.parallel().collect(Collectors.toList());

顾名思义,当使用顺序方式去遍历时,每个item读完后再读下一个item。而使用并行去遍历时,数组会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。

3.2.1并行流原理:

List originalList = someData;
split1 = originalList(0, mid);//将数据分小部分
split2 = originalList(mid,end);
new Runnable(split1.process());//小部分执行操作
new Runnable(split2.process());
List revisedList = split1 + split2;//将结果合并

大家对hadoop有稍微了解就知道,里面的 MapReduce  本身就是用于并行处理大数据集的软件框架,其 处理大数据的核心思想就是大而化小,分配到不同机器去运行map,最终通过reduce将所有机器的结果结合起来得到一个最终结果,与MapReduce不同,Stream则是利用多核技术可将大数据通过多核并行处理,而MapReduce则可以分布式的。

3.2.2顺序与并行性能测试对比

如果是多核机器,理论上并行流则会比顺序流快上一倍,下面是测试代码

long t0 = System.nanoTime();//初始化一个范围100万整数流,求能被2整除的数字,toArray()是终点方法int a[]=IntStream.range(0, 1_000_000).filter(p -> p % 2==0).toArray();long t1 = System.nanoTime();//和上面功能一样,这里是用并行流来计算int b[]=IntStream.range(0, 1_000_000).parallel().filter(p -> p % 2==0).toArray();long t2 = System.nanoTime();//我本机的结果是serial: 0.06s, parallel 0.02s,证明并行流确实比顺序流快
System.out.printf("serial: %.2fs, parallel %.2fs%n", (t1 - t0) * 1e-9, (t2 - t1) * 1e-9);

3.3关于Folk/Join框架

应用硬件的并行性在java 7就有了,那就是 java.util.concurrent 包的新增功能之一是一个 fork-join 风格的并行分解框架,同样也很强大高效,有兴趣的同学去研究,这里不详谈了,相比Stream.parallel()这种方式,我更倾向于后者。

4.总结

如果没有lambda,Stream用起来相当别扭,他会产生大量的匿名内部类,比如上面的3.1.2map例子,如果没有default method,集合框架更改势必会引起大量的改动,所以lambda+default method使得jdk库更加强大,以及灵活,Stream以及集合框架的改进便是最好的证明。

原文出处点击这里

转载于:https://www.cnblogs.com/UncleWang001/p/9843473.html

解开lambda最强作用的神秘面纱相关推荐

  1. 解开VC++调用.Net DLL的神秘面纱

    这段时间有个项目是需要使用vc++的程序访问.Net的类,在网上搜过很多文章,大致有两个方法: 将.Net程序编译成COM,并让C++代码访问COM组件进行调用. 另一个方法使用CRL编译选项,让.N ...

  2. 解开Future的神秘面纱之任务执行

    此文承接之前的博文 解开Future的神秘面纱之取消任务 补充一些任务执行的一些细节,并从全局介绍程序的运行情况. 任务提交到执行的流程 前文我们已经了解到一些Future的实现细节,这里我们来梳理一 ...

  3. C ++匿名函数:揭开C++ Lambda表达式的神秘面纱

    潜意识编程:揭秘C++ Lambda表达式的神秘面纱 Subconscious Programming: Unveiling the Mystery of C++ Lambda Expressions ...

  4. 揭开PC-Lint9的神秘面纱

    前言 今天,又定位了一个令人懊恼的C++内存使用异常问题,最终结果,竟然是减少接口类的方法后,为了避免编译错误,顺手添加的强制类型转换导致的. 对于这样的问题,我们碰到很多很多次了.没有这样的问题,我 ...

  5. 【入行必修】 揭开 AI人工智能工程师 三大岗位 工作内容的 神秘面纱!

    揭开 AI人工智能工程师 三大岗位 工作内容的 神秘面纱! 引言 AI原本是一个专业领域,没什么特别的.作为码农一枚,笔者的工作内容正好在这个领域. 近来这一年左右时间里,连续发生了多件事情,使得笔者 ...

  6. 揭开 Growth Hacking 的神秘面纱(番外篇)+ 大结局

    揭开 Growth Hacking 的神秘面纱(番外篇)+ 大结局 覃超帝国兴亡史  12月11日 11:45 FACEBOOK  互联网  分类 :互联网 阅读:1527 抢沙发 Growth Ha ...

  7. 揭开人类语言的神秘面纱:从理解到处理自然语言

    https://www.toutiao.com/a6709740042509615619/ 随着人工智能的进步和技术变得越来越复杂,我们希望现有的概念能够接受这种变化或者改变自己.同样,在自然语言的计 ...

  8. exchange揭开拨号音还原法的神秘面纱

    之前exchange揭开拨号音还原法的神秘面纱英文版本的翻译,用了两周的时间翻译出来!图片感觉很小,可以下载附件直接查看,会更好! 揭开exchange拨号音恢复的方法(第一部分) 在这三部分系列里, ...

  9. AlphaGo技术剖析:揭开围棋大脑的神秘面纱

    ● 每周一言 智能所体现的思维与认知,没有标准. 导语 围棋,起源于我国尧舜时期,自古以来备受追捧,蕴含着中华文化的丰富内涵.有别于象棋和国际象棋,围棋棋盘之大,玩法千变万化,其落子的可能性更是不可估 ...

最新文章

  1. 混迹于IT纯屌界中独一无二的丸子
  2. javascript小实例,多种方法实现数组去重问题
  3. 浅谈 Vue 项目优化
  4. 【学习笔记】第五章——I/O(设备分类、控制方式、软件层次结构、假脱机、缓冲)
  5. 批处理 安卓一键打包脚本快速解析
  6. python学生管理系统(函数方法)_(python函数)学生管理系统
  7. 【OpenCV】图像金字塔
  8. 服务计算与服务生态系统 第一章测验题答案
  9. Linux下安装Nginx完整教程及常见错误解决方案
  10. js:使用a标签下载图片及pdf文件等资源
  11. Windows10一键优化工具 v4.0.25
  12. python将图片base流保存为图片文件
  13. VueH5页面跳转高德地图导航
  14. 5个好用的样机素材网站
  15. 苹果公司是如何“驻厂“管理供应商的
  16. 李子柒停更半年后,网红经济的“二元一次方程式”解开了吗?
  17. 微信文章如何采集php,记录微信公众号历史文章采集(二、js代码完善和数据库建立)...
  18. 精雕细琢见真章《STM32Cube高效开发教程》
  19. Java 运算符中 前++ 和后++ 的区别详解
  20. 在KVM最小化搭建openstack平台 --快速部署openstack

热门文章

  1. echarts做渐变色象形图
  2. 史上最全架构师知识图谱(纯干货)
  3. jquery所有版本在线引用全
  4. V3000完全拆解【转帖】
  5. html返回到分页不会重置,ngx-pagination - 重置分页到第一页
  6. camx 马达的MSM_ACTUATOR_WRITE_DAC 操作
  7. 淘宝镜像cnpm下载
  8. 手把手教你如何搭建一个自己的安卓快速开发框架之带你做自己的APP(二)
  9. Linux使用光盘镜像配置本地yum源(免于重复挂载)
  10. 纪念我的第一个WP7软件