77
88> 函数式编程语言操纵代码片段就像操作数据一样容易。 虽然 Java 不是函数式语言,但 Java 8 Lambda 表达式和方法引用 (Method References) 允许你以函数式编程。
99
10- 在计算机时代早期,内存是稀缺和昂贵的。几乎每个人都用汇编语言编程。人们对编译器有所了解,但仅仅想到编译生成的代码肯定会比手工编码多了很多字节 。
10+ 在计算机时代早期,内存是稀缺和昂贵的。几乎每个人都用汇编语言编程。人们对编译器有所了解,但仅仅想到编译生成的代码肯定会比手工编码多很多字节 。
1111
12- 通常,只是为了使程序适合有限的内存,程序员通过修改内存中的代码来保存代码空间 ,以便在程序执行时执行不同的操作。这种技术被称为** 自修改代码** (self-modifying code)。只要程序足够小,少数人可以维护所有棘手和神秘的汇编代码,你就可以让它运行起来。
12+ 通常,只是为了使程序适合有限的内存,程序员通过修改内存中的代码来节省代码空间 ,以便在程序执行时执行不同的操作。这种技术被称为** 自修改代码** (self-modifying code)。只要程序足够小,少数人可以维护所有棘手和神秘的汇编代码,你就可以让它运行起来。
1313
14- 随着内存和处理器变得更便宜、更快。C 语言出现并被大多数汇编程序员认为更“高级”。人们发现使用 C 可以显著提高生产力。同时,创建自修改代码仍然不难。
14+ 随着内存和处理器变得更便宜、更快。C 语言出现并被大多数汇编程序员认为更“高级”。人们发现使用 C 可以显著提高生产力。同时,使用 C 创建自修改代码仍然不难。
1515
1616随着硬件越来越便宜,程序的规模和复杂性都在增长。这一切只是让程序工作变得困难。我们想方设法使代码更加一致和易懂。使用纯粹的自修改代码造成的结果就是:我们很难确定程序在做什么。它也难以测试:除非你想一点点测试输出,代码转换和修改等等过程?
1717
@@ -25,7 +25,7 @@ OO(object oriented,面向对象)是抽象数据,FP(functional programm
2525
2626纯粹的函数式语言在安全性方面更进一步。它强加了额外的约束,即所有数据必须是不可变的:设置一次,永不改变。将值传递给函数,该函数然后生成新值但从不修改自身外部的任何东西(包括其参数或该函数范围之外的元素)。当强制执行此操作时,你知道任何错误都不是由所谓的副作用引起的,因为该函数仅创建并返回结果,而不是其他任何错误。
2727
28- 更好的是,“不可变对象和无副作用”范例解决了并发编程中最基本和最棘手的问题之一 (当程序的某些部分同时在多个处理器上运行时)。这是可变共享状态的问题,这意味着代码的不同部分(在不同的处理器上运行)可以尝试同时修改同一块内存(谁赢了?没人知道)。如果函数永远不会修改现有值但只生成新值,则不会对内存产生争用,这是纯函数式语言的定义。 因此,经常提出纯函数式语言作为并行编程的解决方案(还有其他可行的解决方案)。
28+ 更好的是,“不可变对象和无副作用”范式解决了并发编程中最基本和最棘手的问题之一 (当程序的某些部分同时在多个处理器上运行时)。这是可变共享状态的问题,这意味着代码的不同部分(在不同的处理器上运行)可以尝试同时修改同一块内存(谁赢了?没人知道)。如果函数永远不会修改现有值但只生成新值,则不会对内存产生争用,这是纯函数式语言的定义。 因此,经常提出纯函数式语言作为并行编程的解决方案(还有其他可行的解决方案)。
2929
3030需要提醒大家的是,函数式语言背后有很多动机,这意味着描述它们可能会有些混淆。它通常取决于各种观点:“为并行编程”,“代码可靠性”和“代码创建和库复用”。[ ^ 1 ] 同时,函数式编程的参数能帮助程序员创建更快更健壮的代码 —— 部分仍然只是假设。虽然已有一些好的范例[ ^ 2 ] ,但我们还不能证明纯函数式语言就是解决编程问题的最佳方法。
3131
@@ -102,36 +102,36 @@ Hello
102102Hello there Hello there
103103```
104104
105- ** Strategy** 接口提供了单一 ` approach() ` 方法来承载函数式功能。通过实现不同的 ** Strategy** 对象,我们可以创建不同的行为。
105+ ** Strategy** 接口提供了单一的 ` approach() ` 方法来承载函数式功能。通过创建不同的 ** Strategy** 对象,我们可以创建不同的行为。
106106
107107传统上,我们通过创建一个实现 ** Strategy** 接口的类来实现此行为,比如在 ** Soft** 。
108108
109109- ** [ 1] ** 在 ** Strategize** 中,** Soft** 作为默认策略,在初始化构造函数中赋值的。
110110
111- - ** [ 2] ** 一种略显冗长且更自发的方法是创建一个 ** 匿名内部类** 。即使这样,仍有相当数量的冗余代码。你总是要仔细观察:“哦,原来这样,这里使用了匿名内部类。”
111+ - ** [ 2] ** 一种略显简短且更自发的方法是创建一个 ** 匿名内部类** 。即使这样,仍有相当数量的冗余代码。你总是要仔细观察:“哦,原来这样,这里使用了匿名内部类。”
112112
113113- ** [ 3] ** Java 8 的 Lambda 表达式。由箭头 ` -> ` 分隔开参数和函数体,箭头左边是参数,箭头右侧是从 Lambda 返回的表达式,即函数体。这实现了与定义类、匿名内部类相同的效果,但代码少得多。
114114
115115- ** [ 4] ** Java 8 的** 方法引用** ,由 ` :: ` 区分。在 ` :: ` 的左边是类或对象的名称,在 ` :: ` 的右边是方法的名称,但没有参数列表。
116116
117117- ** [ 5] ** 在使用默认的 ** Soft** ** strategy** 之后,我们逐步遍历数组中的所有 ** Strategy** ,并使用 ` changeStrategy() ` 方法将每个 ** Strategy** 放入 变量 ` s ` 中。
118118
119- - ** [ 6] ** 现在,每次调用 ` communic() ` 都会产生不同的行为,具体取决于此刻正在使用的策略** 代码对象** 。我们传递的是行为,而非仅数据。[ ^ 3 ]
120-
121- 在 Java 8 之前,我们能够通过 ** [ 1] ** 和 ** [ 2] ** 的方式传递功能。然而,它的读写语法非常笨拙,并且我们别无选择。方法引用和 Lambda 表达式的出现让我们可以在需要时** 传递功能** ,而不是仅在必要才这么做。
119+ - ** [ 6] ** 现在,每次调用 ` communicate() ` 都会产生不同的行为,具体取决于此刻正在使用的策略** 代码对象** 。我们传递的是行为,而非仅数据。[ ^ 3 ]
122120
121+ 在 Java 8 之前,我们能够通过 ** [ 1] ** 和 ** [ 2] ** 的方式传递功能。然而,这种语法的读写非常笨拙,并且我们别无选择。方法引用和 Lambda 表达式的出现让我们可以在需要时** 传递功能** ,而不是仅在必要才这么做。
123122
124123<!-- Lambda Expressions -->
124+
125125## Lambda表达式
126126
127127
128128Lambda 表达式是使用** 最小可能** 语法编写的函数定义:
129129
1301301 . Lambda 表达式产生函数,而不是类。 在 JVM(Java Virtual Machine,Java 虚拟机)上,一切都是一个类,因此在幕后执行各种操作使 Lambda 看起来像函数 —— 但作为程序员,你可以高兴地假装它们“只是函数”。
131131
132- 2 . Lambda 语法尽可能多 ,这正是为了使 Lambda 易于编写和使用。
132+ 2 . Lambda 语法尽可能少 ,这正是为了使 Lambda 易于编写和使用。
133133
134- 我们在 ` Strategize.java ` 中看到了一个 Lambda 表达式,但还有其他语法变体:
134+ 我们在 ** Strategize.java** 中看到了一个 Lambda 表达式,但还有其他语法变体:
135135
136136``` java
137137// functional/LambdaExpressions.java
@@ -255,7 +255,7 @@ public class RecursiveFactorial {
255255
256256这里,` fact ` 是一个静态变量。 注意使用三元 ** if-else** 。 递归函数将一直调用自己,直到 ` i == 0 ` 。所有递归函数都有“停止条件”,否则无限递归并报异常。
257257
258- 我们可以将 ` Fibonacci ` 序列改为递归 Lambda 表达式来实现,这次使用实例变量:
258+ 我们可以将 ` Fibonacci ` 序列改为使用递归 Lambda 表达式来实现,这次使用实例变量:
259259
260260``` java
261261// functional/RecursiveFibonacci.java
@@ -295,9 +295,10 @@ public class RecursiveFibonacci {
29529555
296296```
297297
298- 将 ` Fibonacci ` 序列对中的最后两个元素求和来产生下一个元素 。
298+ 将 ` Fibonacci ` 序列中的最后两个元素求和来产生下一个元素 。
299299
300300<!-- method references-->
301+
301302## 方法引用
302303
303304
@@ -366,7 +367,7 @@ Help!
366367
367368** [ 3] ** ` hello() ` 也符合 ` call() ` 的签名。
368369
369- ** [ 4] ** 就像是 ` help() ` ,静态内部类中的非静态方法 。
370+ ** [ 4] ** ` help() ` 也符合,它是静态内部类中的非静态方法 。
370371
371372** [ 5] ** ` assist() ` 是静态内部类中的静态方法。
372373
0 commit comments