Skip to content

Commit 9015594

Browse files
authored
Merge pull request lingcoder#210 from xiangflight/master
revision[13] 作为闭包的内部类
2 parents dcff5d4 + b2c4b99 commit 9015594

File tree

1 file changed

+7
-6
lines changed

1 file changed

+7
-6
lines changed

docs/book/13-Functional-Programming.md

+7-6
Original file line numberDiff line numberDiff line change
@@ -1048,7 +1048,7 @@ O
10481048

10491049
**闭包**(Closure)一词总结了这些问题。 它非常重要,利用闭包可以轻松生成函数。
10501050

1051-
考虑一个更复杂的 Lambda,它使用函数作用域之外的变量。 返回该函数会发生什么? 也就是说,当你调用函数时,它对那些 “外部 ”变量引用了什么? 如果语言不能自动解决这个问题,那将变得非常具有挑战性。 能够解决这个问题的语言被称为**支持闭包**,或者叫作在词法上限定范围( 也使用术语变量捕获 )。Java 8 提供了有限但合理的闭包支持,我们将用一些简单的例子来研究它。
1051+
考虑一个更复杂的 Lambda,它使用函数作用域之外的变量。 返回该函数会发生什么? 也就是说,当你调用函数时,它对那些 “外部 ”变量引用了什么? 如果语言不能自动解决这个问题,那将变得非常具有挑战性。 能够解决这个问题的语言被称为**支持闭包**,或者叫作在词法上限定范围( 也使用术语*变量捕获* )。Java 8 提供了有限但合理的闭包支持,我们将用一些简单的例子来研究它。
10521052

10531053
首先,下例函数中,方法返回访问对象字段和方法参数。代码示例:
10541054

@@ -1094,7 +1094,7 @@ public class SharedStorage {
10941094

10951095
每次调用 `getAsInt()` 都会增加 `i`,表明存储是共享的。
10961096

1097-
如果 `i``makeFun()` 的本地怎么办? 在正常情况下,当 `makeFun()` 完成时 `i` 就消失。 但它仍然编译
1097+
如果 `i``makeFun()` 的局部变量怎么办? 在正常情况下,当 `makeFun()` 完成时 `i` 就消失。 但它仍可以编译
10981098

10991099
```java
11001100
// functional/Closure2.java
@@ -1126,7 +1126,7 @@ public class Closure3 {
11261126
}
11271127
```
11281128

1129-
`x``i` 的操作都犯了同样的错误:从 Lambda 表达式引用的局部变量必须是 `final` 或者实 `final` 效果的。
1129+
`x``i` 的操作都犯了同样的错误:从 Lambda 表达式引用的局部变量必须是 `final` 或者是等同 `final` 效果的。
11301130

11311131
如果使用 `final` 修饰 `x``i`,就不能再递增它们的值了。代码示例:
11321132

@@ -1165,7 +1165,7 @@ public class Closure5 {
11651165
}
11661166
```
11671167

1168-
我们可以通过将 `final` 关键字应用于变量声明来实现**等同 final 效果**, 不用更改任何其余代码。 实际上它就是具备 `final` 效果的,只是没有明确说明。
1168+
**等同 final 效果**意味着可以在变量声明前加上 **final** 关键字而不用更改任何其余代码。 实际上它就是具备 `final` 效果的,只是没有明确说明。
11691169

11701170
通过在闭包中使用 `final` 关键字提前修饰变量 `x``i` , 我们解决了 `Closure5.java` 中的问题。代码示例:
11711171

@@ -1206,7 +1206,7 @@ public class Closure7 {
12061206
}
12071207
```
12081208

1209-
编译器非常智能,它能识别变量 `i` 的值正在被更改。 对于包装类型的处理可能比较特殊,所以让我们使用下面的 List 的例子。代码示例
1209+
编译器非常智能,它能识别变量 `i` 的值被更改过了。 对于包装类型的处理可能比较特殊,因此我们尝试下 **List**
12101210

12111211
```java
12121212
// functional/Closure8.java
@@ -1244,7 +1244,7 @@ public class Closure8 {
12441244
[1, 96]
12451245
```
12461246

1247-
可以看到,这次一切正常。我们改变了 List 的值却没产生编译时错误。通过观察本例的输出结果,我们发现这看起来非常安全。这是因为每次调用 `makeFun()` 时,其实都会创建并返回一个全新的 `ArrayList`。 也就是说,每个闭包都有自己独立的 `ArrayList` 他们不能互相干扰和共享
1247+
可以看到,这次一切正常。我们改变了 **List** 的值却没产生编译时错误。通过观察本例的输出结果,我们发现这看起来非常安全。这是因为每次调用 `makeFun()` 时,其实都会创建并返回一个全新的 `ArrayList`。 也就是说,每个闭包都有自己独立的 `ArrayList`, 它们之间互不干扰
12481248

12491249
**注意**我已经声明 `ai``final` 的了。尽管在这个例子中你可以去掉 `final` 并得到相同的结果(试试吧!)。 应用于对象引用的 `final` 关键字仅表示不会重新赋值引用。 它并不代表你不能修改对象本身。
12501250

@@ -1271,6 +1271,7 @@ public class Closure9 {
12711271
让我们回顾一下 `Closure1.java`。那么现在问题来了:为什么变量 `i` 被修改编译器却没有报错呢。 它既不是 `final` 的,也不是**等同 final 效果**的。因为 `i` 是外围类的成员,所以这样做肯定是安全的(除非你正在创建共享可变内存的多个函数)。是的,你可以辩称在这种情况下不会发生变量捕获(Variable Capture)。但可以肯定的是,`Closure3.java` 的错误消息是专门针对局部变量的。因此,规则并非只是“在 Lambda 之外定义的任何变量必须是 `final` 的或**等同 final 效果**那么简单。相反,你必须考虑捕获的变量是否是**等同 final 效果**的。 如果它是对象中的字段,那么它拥有独立的生存周期,并且不需要任何特殊的捕获,以便稍后在调用 Lambda 时存在。
12721272

12731273
<!-- Inner Classes as Closures -->
1274+
12741275
### 作为闭包的内部类
12751276

12761277
我们可以复制我们的例子使用匿名内部类:

0 commit comments

Comments
 (0)