如何避免Lambda表达式中的“副作用”?代码举例讲解

Lambda 表达式中所谓的“副作用”指的是对 Lambda 表达式外部变量的修改。由于 Lambda 表达式可以捕获外部变量,这可能会产生一些意料之外的副作用。

要避免 Lambda 表达式中的副作用,有以下几点要注意:

  1. 不要修改外部 final 变量的值。
    例如:
final int num = 1;
Consumer<Integer> consumer = (x) -> num = 2; // 错误,会修改 final 变量 

这会产生副作用,修改了外部 final 变量 num 的值,导致意料之外的行为,所以是错误的。

  1. 只捕获有效的 final 变量或 effectively final 变量。
    effectively final 变量指在 Lambda 表达式创建后不会被更改的变量。
    例如:
int num = 1;  
Consumer<Integer> consumer = (x) -> doSomething(x + num);  
num = 2; // 错误,这会产生副作用 

这里 num 作为自由变量被 Lambda 捕获,本应是 effectively final 变量,但是之后被修改了,所以这有副作用, 是错误的。

  1. 不要在 Lambda 内部修改外部的对象状态。
    例如:
List<Integer> list = new ArrayList<>();
Consumer<Integer> consumer = (x) -> list.add(x); 

这里 Lambda 表达式直接修改了外部 list 对象的状态,这也是一种副作用,应该避免。

总之,要避免 Lambda 表达式中的副作用,主要关注外部变量的修改以及对象状态的改变。Lambda 表达式应该是无状态的、不可变的,避免产生任何副作用。一个纯粹的 Lambda 表达式只会根据输入参数计算输出结果,不会修改外界任何状态。