Java 中 Lambda 变量捕获

Java 中 lambda 的变量捕获是值的捕获,也就是直接把捕获的变量拷贝一份,这意味着对于栈上的变量,

  1. 如果在 lambda 声明之后被重新赋值了,lambda 里还是旧的值
  2. 如果在 lambda 中想对其赋值,修改数据,对原始变量是不会生效的

所以 Java 干脆禁止这样做,要求它们必须是 final 或者 effectively final(即未加 final 修饰,但在 lambda 声明之后无赋值操作)的。
当然如果真的需要改变原始的值的话,IDE 会提示你可以用 Atomic 类或者一个单元素的数组包装一下,曲线救国。这样捕获时是将 Atomic 对象或者数组变量拷贝一份,而他们指向的数据都是堆上的同一份数据,变相实现引用捕获。

Koltin 中 Lambda 变量捕获

随便写个 demo 反编译下可以发现如果你在 lambda 中对捕获的变量有赋值操作,在 JVM 平台上编译器就会自动帮你把变量包装成一个 Ref 对象,原理跟上面提到的 Java 中的解决方式本质上是一样的。参考 Ref.java