## Lambda表达式变量作用域

public static void repeatMessage(String text, int delay) {
ActionListener listener = event -> {
System.out.println(text);
Toolkit.getDefaultToolkit().beep();
};
new Timer(delay, listener).start();
}

@FunctionalInterface
interface RepeatMessage {
void repeatMessage(String message, int times);
}

public class LambdaTest {

public static void main(String[] args) throws Exception {
int times, i;
RepeatMessage repeatMessage = (msg, times) -> {
for (int i = 0; i < times; i++) {
System.out.println(msg);
}
}
}
}

The body of a lambda expression has the same scope as a nested block.

## 有效的final (effectively final)

Java对于Lambda中捕获的自由变量有一个非常重要的限定：该变量必须是effectively final的。所谓effectively final简单理解就是这个变量一旦初始化之后就不能再重新赋值了(An effectively final variable is a variable that is never assigned a new value after it has been initialized.)。这样限定的主要原因是Lambda表达式可能会并发执行，在里面修改捕获的变量的值可能会产生问题。

### 场景1

Certain variables that are not declared final may instead be considered effectively final.

A local variable or a method, constructor, lambda, or exception parameter is effectively final if it is not final but it never occurs as the left hand operand of an assignment operator (15.26) or as the operand of a prefix or postfix increment or decrement operator (15.14, 15.15).

### 场景2

In addition, a local variable whose declaration lacks an initializer is effectively final if all of the following are true:

• It is not final.
• Whenever it occurs as the left-hand operand of an assignment operator, it is definitely unassigned and not definitely assigned before the assignment (that is, it is definitely unassigned and not definitely assigned after the right-hand operand of the assignment) (16).
• It never occurs as the operand of a prefix or postfix increment or decrement operator.

Examples of effectively final:

void m1(int x) {
int y = 1;
foo(() -> x+y);
// Legal: x and y are both effectively final.
// 这个好理解，x没有被赋值过，y只被赋值过一次。
}

void m2(int x) {
int y;
y = 1;
foo(() -> x+y);
// Legal: x and y are both effectively final.
// 这个也好理解，x没有被赋值过，y第一次只声明了，后面只被赋值过一次。
}

void m3(int x) {
int y;
if (..) y = 1;
foo(() -> x+y);
// Illegal: y is effectively final, but not definitely assigned.
// 这里y不是有效的final的原因主要是不符合"明确的赋值(definitely assigned)"的限定，因为如果if不成立，y就没有被赋值；if成立了，y又被赋值了。
}

void m4(int x) {
int y;
if (..) y = 1;
else y = 2;
foo(() -> x+y);
// Legal: x and y are both effectively final.
// 这里y声明之后，肯定会被赋值，且只会被赋一次值(不是在if中，就是在else中)
}

void m5(int x) {
int y;
if (..) y = 1;
y = 2;
foo(() -> x+y);
// Illegal: y is not effectively final.
// 这里y可能会被赋两次值
}

void m6(int x) {
foo(() -> x+1);
x++;
// Illegal: x is not effectively final.
// 这里x使用了自加操作符
}

void m7(int x) {
foo(() -> x=1);
// Illegal: x is not effectively final.
// 这里x是方法的参数，不是局部变量，所以只能用场景1来评判。而x用作了赋值操作符的左值，所以不是有效的final变量。
}

void m8() {
int y;
foo(() -> y=1);
// Illegal: y is not definitely assigned before the lambda (see 15.27.2)
// 这个稍微难理解一点，之前有说过，Lambda捕获的自由变量一定要是有效的final，而y之前只声明了，并没有只确切的初始化过一次，所以肯定不是有效的final。
}

void m9(String[] arr) {
for (String s : arr) {
foo(() -> s);
// Legal: s is effectively final (it is a new variable on each iteration)
}
}

void m10(String[] arr) {
for (int i = 0; i < arr.length; i++) {
foo(() -> arr[i]);
// Illegal: i is not effectively final (it is incremented)
// 这里i使用了自加操作符
}
}

If a variable is effectively final, adding the final modifier to its declaration will not introduce any compile-time errors. Conversely, a local variable or parameter that is declared final in a valid program becomes effectively final if the final modifier is removed.

Reference

• Core Java Volume I