diff --git a/docs/book/13-Functional-Programming.md b/docs/book/13-Functional-Programming.md index fc6af24..cf7b192 100644 --- a/docs/book/13-Functional-Programming.md +++ b/docs/book/13-Functional-Programming.md @@ -1274,7 +1274,7 @@ public class Closure9 { ### 作为闭包的内部类 -我们可以复制我们的例子使用匿名内部类: +我们可以使用匿名内部类重写之前的例子: ```java // functional/AnonymousClosure.java @@ -1300,7 +1300,7 @@ public class AnonymousClosure { ## 函数组合 -函数组合(Function Composition)意为“多个函数组合成新函数”。它通常是函数式编程的基本组成部分。在前面的 `TransformFunction.java` 类中,有一个使用 `andThen()` 的函数组合示例。在 `java.util.function` 包里包含支持函数组合的一些接口方法 [^7]。 +函数组合(Function Composition)意为“多个函数组合成新函数”。它通常是函数式编程的基本组成部分。在前面的 `TransformFunction.java` 类中,有一个使用 `andThen()` 的函数组合示例。一些 `java.util.function` 接口中包含支持函数组合的方法 [^7]。 | 组合方法 | 支持接口 | | :----- | :----- | @@ -1343,7 +1343,7 @@ _fter _ll _mbul_nces 这里我们重点看正在创建的新函数 `f4`。它调用 `apply()` 的方式与常规几乎无异[^8]。 -当 `f1` 获得字符串时,它已经被`f2` 剥离了前三个字符。这是因为对 `compose(f2)`的调用意味着在 `f1` 之前调用 `f2`。 +当 `f1` 获得字符串时,它已经被`f2` 剥离了前三个字符。这是因为 `compose(f2)` 表示 `f2` 的调用发生在 `f1` 之前。 下例是 `Predicate` 的逻辑运算演示.代码示例: @@ -1376,14 +1376,13 @@ foobaz `p4` 获取到了所有断言并组合成一个更复杂的断言。解读:如果字符串中不包含 `bar` 且长度小于 5,或者它包含 `foo` ,则结果为 `true`。 -正因它产生如此清晰的语法,我在主方法中采用了一些小技巧,并借用了下一章的内容。首先,我创建一个流的字符串对象集合,然后将每个对象传递给 `filter()` 操作。 `filter()` 使用 `p4` 的断言来确定对象的去留。最后我们使用 `forEach()` 和 `println` 方法打印出留下来的对象。 +正因它产生如此清晰的语法,我在主方法中采用了一些小技巧,并借用了下一章的内容。首先,我创建了一个字符串对象的流,然后将每个对象传递给 `filter()` 操作。 `filter()` 使用 `p4` 的断言来确定对象的去留。最后我们使用 `forEach()` 将 `println` 方法引用应用在每个留存的对象上。 从输出结果我们可以看到 `p4` 的工作流程:任何带有 `foo` 的东西都会留下,即使它的长度大于 5。 `fongopuckey` 因长度超出和不包含 `bar` 而被丢弃。 ## 柯里化和部分求值 - [柯里化](https://en.wikipedia.org/wiki/Currying)(Currying)的名称来自于其发明者之一 *Haskell Curry*。他可能是计算机领域唯一名字被命名重要概念的人(另外就是 Haskell 编程语言)。 柯里化意为:将一个多参数的函数,转换为一系列单参数函数。 ```java @@ -1458,7 +1457,7 @@ public class Curry3Args { Hi Ho Hup ``` -对于每个级别的箭头级联(Arrow-cascading),你可以围绕类型声明包装成另一个函数。 +对于每个级别的箭头级联(Arrow-cascading),你在类型声明中包裹了另一个 **Function**。 处理基本类型和装箱时,请使用适当的 **Function** 接口: @@ -1473,7 +1472,7 @@ public class CurriedIntAdd { curriedIntAdd = a -> b -> a + b; IntUnaryOperator add4 = curriedIntAdd.apply(4); System.out.println(add4.applyAsInt(5)); - } + } } ``` @@ -1483,13 +1482,13 @@ public class CurriedIntAdd { 9 ``` -更多柯里化示例,可搜索互联网。通常这些是 Java 以外的语言,理解它们的基本概念,就应该很容易翻译。 +可以在互联网上找到更多的柯里化示例。通常它们是用 Java 之外的语言实现的,但如果理解了柯里化的基本概念,你可以很轻松地用 Java 实现它们。 ## 纯函数式编程 -即使没有函数式支持,像 C 这样的基础语言,也可以按照一定的原则编写纯函数程序。Java 8 让函数式编程更简单,不过我们要确保一切是 `final` 的,同时你的所有方法和函数没有副作用。因为 Java 在本质上并非是不可变语言,我们无法通过编译器查错。 +即使没有函数式支持,像 C 这样的基础语言,也可以按照一定的原则编写纯函数式程序。Java 8 让函数式编程更简单,不过我们要确保一切是 `final` 的,同时你的所有方法和函数没有副作用。因为 Java 在本质上并非是不可变语言,我们无法通过编译器查错。 这种情况下,我们可以借助第三方工具[^9],但使用 Scala 或 Clojure 这样的语言可能更简单。因为它们从一开始就是为保持不变性而设计的。你可以采用这些语言来编写你的 Java 项目的一部分。如果必须要用纯函数式编写,则可以用 Scala(需要一些规则) 或 Clojure (需要的规则更少)。虽然 Java 支持[并发编程](./24-Concurrent-Programming.md),但如果这是你项目的核心部分,你应该考虑在项目部分功能中使用 `Scala` 或 `Clojure` 之类的语言。 @@ -1509,7 +1508,7 @@ Lambda 表达式和方法引用并没有将 Java 转换成函数式语言,而 [^1]: 功能粘贴在一起的方法的确有点与众不同,但它仍不失为一个库。 [^2]: 例如,这个电子书是利用 [Pandoc](http://pandoc.org/) 制作出来的,它是用纯函数式语言 [Haskell](https://www.haskell.org/) 编写的一个程序 。 -[^3]: 有时函数式语言将其描述为“代码即数据”。“ +[^3]: 有时函数式语言将其描述为“代码即数据”。 [^4]: 这个语法来自 C++。 [^5]: 我还没有验证过这种说法。 [^6]: 当你理解了[并发编程](./24-Concurrent-Programming.md)章节的内容,你就能明白为什么更改共享变量 “不是线程安全的” 的了。