在开始探索 Lambda 表达式之前,首先我们要知道它因何而生。
本章将介绍 Lambda 表达式产生的原因,以及本书的写作动机和组织结构。
1.1 为什么需要再次修改Java
1996 年 1 月,Java 1.0 发布,此后计算机编程领域发生了翻天覆地的变化。
商业发展需要更复杂的应用,大多数程序都跑在功能强大的多核 CPU 的机器上。
带有高效运行时编译器的 Java 虚拟机(JVM)的出现,使程序员将更多精力放在编写干净、易于维护的代码上,而不是思考如何将每一个 CPU 时钟周期、每字节内存物尽其用。 多核 CPU 的兴起成为了不容回避的事实。
涉及锁的编程算法不但容易出错,而且耗费时间。
人们开发了 java.util.concurrent 包和很多第三方类库,试图将并发抽象化,帮助程序员写出在多核 CPU 上运行良好的程序。
很可惜,到目前为止,我们的成果还远远不够。
开发类库的程序员使用 Java 时,发现抽象级别还不够。
处理大型数据集合就是个很好的例子,面对大型数据集合,Java 还欠缺高效的并行操作。
开发者能够使用 Java 8 编写复杂的集合处理算法,只需要简单修改一个方法,就能让代码在多核 CPU 上高效运行。
为了编写这类处理批量数据的并行类库,需要在语言层面上修改现有的 Java:增加 Lambda 表达式。
当然,这样做是有代价的,程序员必须学习如何编写和阅读使用 Lambda 表达式的代码,但是,这不是一桩赔本的买卖。
与手写一大段复杂、线程安全的代码相比,学习一点新语法和一些新习惯容易很多。
开发企业级应用时,好的类库和框架极大地降低了开发时间和成本,也为开发易用且高效的类库扫清了障碍。
对于习惯了面向对象编程的开发者来说,抽象的概念并不陌生。
面向对象编程是对数据进行抽象,而函数式编程是对行为进行抽象。
现实世界中,数据和行为并存,程序也是如此,因此这两种编程方式我们都得学。
这种新的抽象方式还有其他好处。
不是所有人都在编写性能优先的代码,对于这些人来说,函数式编程带来的好处尤为明显。
程序员能编写出更容易阅读的代码——这种代码更多地表达了业务逻辑的意图,而不是它的实现机制。
易读的代码也易于维护、更可靠、更不容易出错。
在写回调函数和事件处理程序时,程序员不必再纠缠于匿名内部类的冗繁和可读性,函数式编程让事件处理系统变得更加简单。
能将函数方便地传递也让编写惰性代码变得容易,惰性代码在真正需要时才初始化变量的值。
Java 8 还让集合类可以拥有一些额外的方法:default 方法。
程序员在维护自己的类库时,可以使用这些方法。
总而言之,Java 已经不是祖辈们当年使用的 Java 了,嗯,这不是件坏事。
1.2 什么是函数式编程
每个人对函数式编程的理解不尽相同。
但其核心是:在思考问题时,使用不可变值和函数,函数对一个值进行处理,映射成另一个值。
不同的语言社区往往对各自语言中的特性孤芳自赏。
现在谈 Java 程序员如何定义函数式编程还为时尚早,但是,这根本不重要!
我们关心的是如何写出好代码,而不是符合函数式编程风格的代码。
本书将重点放在函数式编程的实用性上,包括可以被大多数程序员理解和使用的技术,帮助他们写出易读、易维护的代码。
1.3 示例
本书中的示例全部都围绕一个常见的问题领域构造:音乐。
具体来说,这些示例代表了在专辑上常常看到的信息,有关术语定义如下。
Ŗ Artist 创作音乐的个人或团队。 Ŗ name:艺术家的名字(例如“甲壳虫乐队”)。 Ŗ members:乐队成员(例如“约翰 · 列侬”),该字段可为空。 Ŗ origin:乐队来自哪里(例如“利物浦”)。
Track专辑中的一支曲目。 Ŗ name:曲目名称(例如《黄色潜水艇》)。
Ŗ Album专辑,由若干曲目组成。 Ŗ name:专辑名(例如《左轮手枪》)。 Ŗ tracks:专辑上所有曲目的列表。 Ŗ musicians:参与创作本专辑的艺术家列表。
本书将使用这个问题讲解如何在正常的业务领域或者 Java 应用中使用函数式编程技术。
也许读者认为这些示例并不完美,但它和真实的业务领域应用比起来足够简单,书中的很多代码都是基于这个简单的模型。
参考资料
《java8 函数式编程》