• Java函数式编程9787121330216
21年品牌 40万+商家 超1.5亿件商品

Java函数式编程9787121330216

正版二手图书,可开发票,请放心购买。

24.09 2.0折 119 八品

仅1件

广东广州
认证卖家担保交易快速发货售后保障

作者【法】Pierre-Yves Saumont(皮埃尔-伊夫斯 索蒙特)

出版社电子工业出版社

ISBN9787121330216

出版时间2018-01

装帧平装

开本其他

定价119元

货号1874294340168831489

上书时间2025-01-02

亿临书店

四年老店
已实名 已认证 进店 收藏店铺

   商品详情   

品相描述:八品
商品描述
前言

译者序

 


 

有幸受邀翻译本书。初见书名,心中不免有几分疑虑,难道又是一本教授怎么使用 Java 8 lambda来进行函数式编程的书吗?翻了几页,方觉自己大误。本书其实意在如何从零开始,逐步理清函数式编程的思维方式并编写基础类库,不仅授之以鱼,而且授之以渔。只不过由于 Java的受众实在太广,所以才使用这门语言罢了。

 

函数式编程有一个至关重要的前提,那就是函数的输出只能取决于函数的参数(我们会在书中看到生成随机数的例子)。初看上去似乎与 Java这门面向对象的语言不搭,但语言只是工具而已,正如你也可以在 Haskell中编写命令式风格的代码一样。在一个不太复杂甚至非并发的常规 Java系统中,由于程序内部状态的改变,多次调用同一个方法的返回值很可能是不一样的,更不用说所带来的副作用了。在函数式编程中,确定的输入决定了确定的输出,这意味着只要参数对了,结果一定在预期中。也就是说,函数式编程没有无法重现的 bug。在这样的前提下,单元测试相对容易实现,而且能极大地增强你的信心。(想想你对目前所在项目的单元测试有多大的信心?)许多个这样的函数复合起来,在不改变信心的同时能够提供更多、更强大的功能,进而带来更大的收益,如无状态的线程安全、必要时才计算的惰性求值、加快多次执行速度的记忆化等。

 

传统的命令式编程是计算机硬件的抽象,源自图灵机,其实就是外部输入、内部状态、对外部的输出以及对内部状态的改变。函数式编程源自 λ演算,即将变量和函数替换为值或表达式并根据运算符进行计算。函数式编程相比命令式编程,代码更简洁、可读性更强,这是因为它的思维方式更倾向于描述什么,而不是怎么做。所以学习过程反而更加自然,并且不需要多么高深的数学基础。可是我们也知道,软件开发没有银弹。新的方法论也会带来新的问题,需要运用新知识来解决。幸运的是,新知识的坑已经有人帮你踩过了,高阶函数、偏应用函数、复合函数、柯里化、闭包……软件开发从来不缺术语。幸好它们并非高不可攀,作者在第 2章中帮你扫清疑虑,并在后续章节中挑战惰性求值、记忆化、状态处理、应用作用还有 actor等更高级的技术。你说 Monad?作者才不告诉你它究竟是什么,但是看完本书你自然就领悟了。

 

函数式编程不是万能药。它有自己擅长的领域,也有自己的弱项。函数式编程是级别更高的抽象。高级别抽象带来的收益就是易读、好写,可是有些低级别的事情(如果你真的需要的话)可能就不容易完成。函数式编程没有副作用,导致无法完成输入 /输出操作。尽管如此,你也会在本书中看到一些解决办法。函数式编程没有变量,因此无法改变循环的终止条件,故而没有循环,严重依赖于用递归来抽象循环。在某些情况下可能会影响性能,所以你还会在本书中看到一些性能与情怀之间的权衡。绝大部分的编程最佳实践都是针对某个特定场景而言的,因此脱离业务场景直接讨论技术并不可取。拥有函数式编程的思维,你就拥有了解决问题的另一种选择,但是条条大路通罗马,千万别钻牛角尖。程序是对现实世界的建模,“不要让世界适应你的模型,要让你的模型适应世界。”

 

高清华

 


 

译者简介

 


 

高清华

 

亚马逊软件研发工程师。工作十多年来,在简洁代码、自动化测试、持续交付、 DevOps等方面都有着丰富的经验。他是《 DevOps实践》译者之一。其技术博客的网址是 http://qinghua.github.io/,希望能以通俗易懂的语言普及 IT技术。

 


 

为什么要函数式编程

 


 

函数式编程中没有赋值语句,因此变量一旦有了值,就不会再改变了。更通俗地说,函数式编程完全没有副作用。除了计算结果,调用函数没有其他作用。这样便消除了 bug的一个主要来源,也使得执行顺序变得无关紧要 —因为没有能够改变表达式值的副作用,可以在任何时候对它求值。这样便把程序员从处理控制流程的负担中解脱出来。由于能够在任何时候对表达式求值,所以可以用变量的值来自由替换表达式,反之亦然 —程序是“引用透明”的。这样的自由度让函数式的程序比它们的一般对手在数学上更易驾驭。 

 

—John Hughes 

 

Why Functional Programming Matters 

 

我称之为十亿美元的错误……我当时的目标是确保所有引用的使用都应该绝对安全,由编译器自动执行检查。但是我无法抵制引入一个空引用的诱惑,仅仅是因为它很容易实现。这导致了无数的错误、漏洞和系统崩溃,它很可能在过去的四十年中造成了十亿美元的痛苦和损害。 

 

—Tony Hoare

 

测试程序可以是一个证明 bug存在的有效方式,但是对于证明 bug不存在还是无可奈何。 

 

—Edsger W. Dijkstra

 

测试本身并不能提高软件质量。测试结果是质量的指标,但它们并不能提高质量。尝试通过增加测试来提高软件质量就像是尝试通过经常称自己的体重来减肥一样。 

 

—Steve McConnell

 

注释的合理运用是为了补偿我们无法成功地在代码中表达自己。 

 

—Robert C. Martin

 

编程的难点并不是解决问题,而是决定要解决什么问题。 

 

—Paul Graham 

 

面向对象编程通过封装变化的部分使代码容易理解。函数式编程通过最小化变化的部分使代码容易理解。 

 

—Michael Feathers

 

我总是发现计划没有用,但是制订计划不可或缺。 

 

—Dwight D. Eisenhower

 

设计软件有两种方法:一种是简单化,使其明显没有缺陷;另一种是复杂化,使其没有明显缺陷。前者要难得多。 

 

—Tony Hoare

 

如果我们询问客户他们想要什么,他们只会说:“更快的马。” 

 

—Henry Ford

 

尽管一些声明式程序员对等式推理( equational reasoning)只会耍嘴皮子,但函数式语言的用户每次运行编译器时都会用到它们,无论他们是否注意到。 

 

—Philip Wadler 

 

How to declare an imperative

 

我们并不试图争取 Lisp程序员;我们在追赶 C++程序员。我们设法在他们到达 Lisp的半路上拽走他们。 —Guy Steele

 

人们“得到”类型,一直用着它们。告诉某人他不能用香蕉来敲钉子并不令其感到惊讶。 

 

—Unknown 

 

TDD代替了类型检查器……正如烈酒代替了悲伤。 —byorgey

 

首先,调试的难度是编写代码的两倍。因此,即使你把代码写得精彩绝伦,根据定义,你还不足以聪明地调试代码。 —Brian W. Kernighan和 P. J. Plauger

 

一旦开始编程,令我们感到惊讶的是,很难让程序按预想的方案正确地工作。不得不靠调试来弄明白。我还记得当意识到我此生的大部分时间都会用于寻找自己程序中的错误时的那一刻。 

 

—Maurice Wilkes (1949) 

 


 

序言

 


 

编程序既有趣又多金。许多人为了乐趣而编程,还能赚钱。从这种意义上说,程序员有点像演员、音乐家或职业足球运动员。似乎是一个梦想,直到作为程序员的你开始负起真正的责任。从这个角度上说,编写游戏或办公应用程序都没有什么大不了的。如果应用程序有一个 bug,你只修复它并发布一个新版本即可。但如果你编写的程序被人们依赖,并且还不能简单地发布一个新版本后让用户们自行安装,那就是另一种情况了。当然, Java并非用于编写监控核电站或控制飞机的应用程序,或者是一个简单的 bug就可能会置人类生命于风险中的系统。但如果你的程序用于管理互联网骨干,你一定不会愿意在奥运会开幕前一天发现一个讨厌的 bug,导致整个国家的电视传输失败。对于这样的程序,你希望确保它可以被证明是正确的。

 

大多数命令式程序无法被证明是正确的。测试只允许我们在测试失败时证明程序不正确。成功的测试说明不了什么问题。你无法证明发布的程序是不正确的。就单线程程序而言,大量的测试也许能够说明你的代码大部分是正确的。但是对于多线程应用程序,条件组合的数量使测试成为不可能。显然,我们需要另一种不同的方式来编写程序。在理想情况下,这种方法将允许我们证明程序是正确的。因为这一般不是完全可能的,所以一个很好的折中是明确分离程序中可以被证明为正确的部分和不能证明为正确的部分。这就是函数式编程技术所能提供的。

 

函数式编程的定义与函数式程序员一样多。有人说函数式编程是用函数编程。这是对的,但它无助于你了解这种编程范式的优势。更重要的是,函数式编程需要将抽象推至极致的理念。它允许明确分离程序中可以被证明为正确的部分与输出取决于外部条件的其他部分。通过这种方式,函数式程序是不太容易产生 bug的程序,它的 bug只会驻留在特定的受限区域。

 

可以采用许多种技术来实现这一目标。使用不可变数据虽然不仅限于函数式编程,但却是这样一种技术。如果数据不能更改,你将不会有任何(不良的)意外,数据不会过期或损坏,没有竞争条件,无须锁住并发访问,也不会有死锁的风险。可以毫无风险地共享不可变数据。你不需要生成防御性副本,那就没有了忘记这样做的风险。另一种技术是抽象控制结构,因此你不必冒着混淆循环索引和退出条件的风险一次又一次地编写相同的结构。完全删除使用 null引用(无论是隐式还是显式)将把你从臭名昭著的 NPE(空指针异常, NullPointerException)中解放出来。通过所有这些技术(还有更多),你可以确信:如果程序通过编译,那它就是正确的(也就是说,它的实现没有 bug)。虽然这样做并不能消除所有可能的 bug,但它更加安全。

 

计算机从一开始就基于寄存器中的可变值使用了命令式范式。正如其他许多被称为“命令式语言”的编程语言一样, Java似乎在很大程度上依赖于这种范式,但根本没有必要。如果你是有经验的 Java程序员,你可能会惊讶地发现无须更改变量的值就可以编写有用的程序。这并非函数式编程的必要条件,但是函数式程序员几乎总是自由自在地用着不可变数据。你可能也难以相信,可以在不使用 if…else结构、 while还有 for循环的情况下编写程序。

 




作者简介

Pierre-Yves Saumont是一名拥有三十年设计和构建企业级软件的Java开发者。他目前是Alcatel-Lucent Submarine Networks公司的一名软件研发工程师。
高清华***软件研发工程师。工作十多年来,在简洁代码、自动化测试、持续交付、DevOps 等方面都有着丰富的经验。《DevOps 实践》译者之一。技术博客:http://qinghua.github.io/,希望能以通俗易懂的语言普及IT 技术。



目录
目录 

第1章 什么是函数式编程............................. 1 

1.1 函数式编程是什么 .............................................2 

1.2 编写没有副作用的程序 .....................................4 

1.3 引用透明如何让程序更安全 .............................6 

1.4 函数式编程的优势 .............................................7 

1.5 用代换模型来推断程序 .....................................8 

1.6 将函数式原则应用于一个简单的例子 .............9 

1.7 抽象到极致 .15 

1.8 总结 .............16 

第2章 在Java中使用函数 ............................17 

2.1 什么是函数 .18 

2.1.1 现实世界里的函数 ...............................18 

2.2 Java中的函数 ....................................................24 

2.2.1 函数式的方法 .......................................24 

2.2.2 Java的函数式接口与匿名类 ...............30 

2.2.3 复合函数 ...............................................31 

2.2.4 多态函数 ...............................................32 

2.2.5 通过 lambda简化代码 ..........................33 

2.3 高级函数特性 ...................................................36 

2.3.1 多参函数怎么样 ...................................36 

2.3.2 应用柯里化函数 ...................................37 

2.3.3 高阶函数 ...............................................38 

2.3.4 多态高阶函数 .......................................39 

2.3.5 使用匿名函数 .......................................43 

2.3.6 局部函数 ...............................................45 

2.3.7 闭包 .46 

2.3.8 部分函数应用和自动柯里化 ...............48 

2.3.9 交换部分应用函数的参数 ...................53 

2.3.10 递归函数 .............................................54 

2.3.11 恒等函数 ..............................................56 

2.4 Java 8的函数式接口 .........................................58 

2.5 调试lambda ..59 

2.6 总结 .............62 

第3章 让Java更加函数式 ............................63 

3.1 使标准控制结构具有函数式风格 ...................64 

3.2 抽象控制结构 ...................................................65 

3.2.1 清理代码 ...............................................69 

3.2.2 if … else的另一种方式 ........................73 

3.3 抽象迭代 .....78 

3.3.1 使用映射抽象列表操作 .......................79 

3.3.2 创建列表 ...............................................80 

3.3.3 使用 head和 tail操作...........................81 

3.3.4 函数式地添加列表元素 .......................83 

3.3.5 化简和折叠列表 ...................................83 

3.3.6 复合映射和映射复合 ...........................90 

3.3.7 对列表应用作用 ...................................91 

3.3.8 处理函数式的输出 ...............................92 

3.3.9 构建反递归列表 ...................................93 

3.4 使用正确的类型 ...............................................97 

3.4.1 标准类型的问题 ...................................97 

3.4.2 定义值类型 ...........................................99 

3.4.3 值类型的未来 .....................................103 

3.5 总结 ...........103 

第4章 递归、反递归和记忆化 ................... 104 

4.1 理解反递归和递归 .........................................105 

4.1.1 探讨反递归和递归的加法例子 .........105 

4.1.2 在 Java中实现递归 ............................106 

4.1.3 使用尾调用消除 .................................107 

4.1.4 使用尾递归方法和函数 .....................107 

4.1.5 抽象递归 .............................................108 

4.1.6 为基于栈的递归方法使用一个直接替代品 ...........................................112 

4.2 使用递归函数 .................................................115 

4.2.1 使用局部定义的函数 .........................115 

4.2.2 使函数成为尾递归 .............................116 

4.2.3 双递归函数:斐波那契数列示例 .....117 

4.2.4 让列表的方法变成栈安全的递归 .....120 

4.3 复合大量函数 .................................................123 

4.4 使用记忆化 .....................................................127 

4.4.1 命令式编程中的记忆化 .....................127 

4.4.2 递归函数的记忆化 .............................128 

4.4.3 自动记忆化 .........................................130 

4.5 总结 ...........136 

第5章 用列表处理数据 ............................. 138 

5.1 如何对数据集合进行分类 .............................138 

5.1.1 不同的列表类型 .................................139 

5.1.2 对列表性能的相对期望 .....................140 

5.1.3 时间与空间,时间与复杂度的取舍 .141 

5.1.4 直接修改 .............................................142 

5.1.5 持久化数据结构 .................................143 

5.2 一个不可变、持久化的单链表实现 .............144 

5.3 在列表操作中共享数据 .................................148 

5.3.1 更多列表操作 .....................................150 

5.4 使用高阶函数递归折叠列表 .........................155 

5.4.1 基于堆的 foldRight递归版 ................162 

5.4.2 映射和过滤列表 .................................164 

5.5 总结 ...........167 

第6章 处理可选数据 ................................ 168 

6.1 空指针的问题 .................................................1

—  没有更多了  —

以下为对购买帮助不大的评价

此功能需要访问孔网APP才能使用
暂时不用
打开孔网APP