Skip to content

四火的唠叨

一个纯正程序员的啰嗦

Menu
  • 所有文章
  • About Me
  • 关于四火
  • 旅行映像
  • 独立游戏
  • 资源链接
Menu

Java8 集合中的 Lambda 表达式

Posted on 10/18/201306/23/2019 by 四火

lambda

本文翻译自《Java 8 Explained: Applying Lambdas to Java Collections》。

Lambdas 表达式是 Java 8 的主题,在 Java 平台上我们期待了很久。但是,如果如果我们不在集合中使用它的话,就损失了很大价值。把现有接口迁移成为 lambda 风格接口的问题已经通过 default methods,也就是 defender methods 解决了。在这篇文章里面我们来看一看 Java 集合里面的批量数据操作(bulk operation)。

批量操作

最初的变更文档已经说了,批量操作是 “给 Java 集合框架添加的用以批量操作数据的功能,而它是基于 lambda 函数实现的”。引用的话也就是在说,lambda 移植到 Java 8 对我来说的实际目的,就是它提供了一种新的使用集合的方式,这也是最重要的特性,表达式操作符可以并行执行,并且 lambda 是一个比常规表达式操作符更好的工具。

内部和外部的迭代

历史上,Java 集合是不能够表达内部迭代的,而只提供了一种外部迭代的方式,也就是 for 或者 while 循环。要描述内部迭代,我们需要用到 LambdaJ 这样的类库:

List persons = asList(new Person("Joe"), new Person("Jim"), new Person("John"));
forEach(persons).setLastName("Doe");

从上面的例子可以看出,我们不需要关心 last name 是怎么被设置到每一个 person 对象里面去的,也许这样的行为是支持并发执行的。现在我们可以在 Java 8 中使用类似的表达了:

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

内部迭代其实和集合的批量操作并没有密切的联系,这只是一个小小的特性,借助它我们感受到语法表达上的变化。真正有意思的和批量操作相关的是新的流(stream)API。

流 API

新的 java.util.stream 包已经添加进 JDK 了,现在我们可以借助 Java 8 执行 filter/map/reduce 风格的操作了。

流 API 允许我们声明对数据进行串行或者并行的操作:

List persons = …   // sequential version
Stream stream = persons.stream();   //parallel version
Stream parallelStream = persons.parallelStream();

java.util.stream.Stream 接口提供了批量数据操作的入口,取得了对流实例的引用,我们就可以对集合执行如下有趣的任务了:

Filter

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

List persons = …
Stream personsOver18 = persons.stream().filter(p -> p.getAge() > 18);

Map

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

Stream students = persons.stream()
      .filter(p -> p.getAge() > 18)
      .map(new Function() {
                  @Override
                  public Student apply(Person person) {
                     return new Student(person);
                  }
              });

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

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

Lambda 在把参数传给 map 方法的时候,实际却并没有使用这个参数,那么我们就可以写成这样:

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

Collect

“流” 抽象天生就该是持续的,我们使用流来描述操作,但是如果我们要获取最终结果的话,必须收集流产生的最终结果。Stream API 提供了一系列 “最终” 的方法,collect()方法就是其中的一个,我们借此可以收集操作的最终结果:

List students = persons.stream()
        .filter(p -> p.getAge() > 18)
        .map(Student::new)
        .collect(new Collector>() { … });

幸运的是,大多数情况下你不需要自己实现 Collector 接口,而是利用 Collectors 工具类:

List students = persons.stream()
        .filter(p -> p.getAge() > 18)
        .map(Student::new)
        .collect(Collectors.toList());

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

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

并行和串行

一个使用新的 Stream API 有趣的特性是它从来都不需要所谓串行或者并行的方法,可以从一开始就并行地消费数据,或者在处理流中的任意时刻转为串行的。

List students = persons.stream()
        .parallel()
        .filter(p -> p.getAge() > 18)  // filtering will be performed concurrently
        .sequential()
        .map(Student::new)
        .collect(Collectors.toCollection(ArrayList::new));

这里有隐藏的一点是,数据处理的并行部分会自动地自我管理,不需要我们自己来处理并发的问题。

总结

好了,要结束了。新的 Stream API 和 lambda 表达式给 Java 8 带来了很多新的特性。当然,在这篇文章以外还有很多没有谈及到,但愿很快我可以给你带给你更多有趣的特性。

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》

×Scan to share with WeChat

你可能也喜欢看:

  1. 一段集合操作的不同语言表达
  2. 看 JDK 源码,解几个疑问
  3. 动手实现随机验证码
  4. Java 的日期 API 真烂
  5. 你真的精通 Java 吗?

1 thought on “Java8 集合中的 Lambda 表达式”

  1. 大可 says:
    11/09/2013 at 2:30 PM

    呼呼。。java 的新特性越来越让人有兴趣了。。。谢谢博主的分享。。希望博主多写写新特性的东西。。谢谢。。

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

订阅·联系

四火,啰嗦的程序员一枚,现居西雅图

Amazon Google Groovy Hadoop Haskell Java JavaScript LeetCode Oracle Python Spark 互联网 前端 华为 历史 同步 团队 图解笔记 基础设施 工作 工作流 工具 工程师 应用系统 异步 微博 思考 技术 数据库 曼联 测试 生活 程序员 管理 系统设计 缓存 编码 编程范型 英语 西雅图 设计 评审 问题 面试 项目

分类

  • Algorithm and Data Structure (30)
  • Concurrency and Asynchronization (6)
  • System Architecture and Design (43)
  • Distributed System (18)
  • Tools Frameworks and Libs (13)
  • Storage and Data Access (8)
  • Front-end Development (33)
  • Programming Languages and Paradigms (55)
  • Testing and Quality Assurance (4)
  • Network and Communication (6)
  • Authentication and Authorization (6)
  • Automation and Operation Excellence (13)
  • Big Data and Machine Learning (5)
  • Product Design (7)
  • Hiring and Interviews (14)
  • Project and Team Management (14)
  • Engineering Culture (17)
  • Critical Thinking (25)
  • Career Growth (57)
  • Life Experience and Thoughts (45)

推荐文章

  • 谈谈分布式锁
  • 常见分布式系统设计图解(汇总)
  • 系统设计中的快速估算技巧
  • 从链表存在环的问题说起
  • 技术面试中,什么样的问题才是好问题?
  • 从物理时钟到逻辑时钟
  • 近期面试观摩的一些思考
  • RSA 背后的算法
  • 谈谈 Ops(汇总 + 最终篇):工具和实践
  • 不要让业务牵着鼻子走
  • 倔强的程序员
  • 谈谈微信的信息流
  • 评审的艺术——谈谈现实中的代码评审
  • Blog 安全问题小记
  • 求第 K 个数的问题
  • 一些前端框架的比较(下)——Ember.js 和 React
  • 一些前端框架的比较(上)——GWT、AngularJS 和 Backbone.js
  • 工作流系统的设计
  • Spark 的性能调优
  • “残酷” 的事实
  • 七年工作,几个故事
  • 从 Java 和 JavaScript 来学习 Haskell 和 Groovy(汇总)
  • 一道随机数题目的求解
  • 层次
  • Dynamo 的实现技术和去中心化
  • 也谈谈全栈工程师
  • 多重继承的演变
  • 编程范型:工具的选择
  • GWT 初体验
  • java.util.concurrent 并发包诸类概览
  • 从 DCL 的对象安全发布谈起
  • 不同团队的困惑
  • 不适合 Hadoop 解决的问题
  • 留心那些潜在的系统设计问题
  • 再谈大楼扔鸡蛋的问题
  • 几种华丽无比的开发方式
  • 我眼中的工程师文化
  • 观点的碰撞
  • 谈谈盗版软件问题
  • 对几个软件开发传统观点的质疑和反驳
  • MVC 框架的映射和解耦
  • 编程的未来
  • DAO 的演进
  • 致那些自嘲码农的苦逼程序员
  • Java 多线程发展简史
  • 珍爱生命,远离微博
  • 网站性能优化的三重境界
  • OSCache 框架源码解析
  • “ 你不适合做程序员”
  • 画圆画方的故事

近期评论

  • + 1.943624 BTC.NEXT - https://graph.org/Ticket--58146-05-02?hs=9a9c6f8dfe3cdbe0074006e3e640b19b& on 所有文章
  • Anonymous on 闲聊投资:亲自体验和护城河
  • 四火 on 关于近期求职的近况和思考
  • YC on 关于近期求职的近况和思考
  • mafulong on 常见分布式基础设施系统设计图解(四):分布式工作流系统
  • 四火 on 常见分布式基础设施系统设计图解(八):分布式键值存储系统
  • Anonymous on 我裸辞了
  • https://umlcn.com on 资源链接
  • Anonymous on 我裸辞了
  • Dylan on 我裸辞了
© 2025 四火的唠叨 | Powered by Minimalist Blog WordPress Theme