为什么lamda不能修改外部引用的变量?

  • lamda表达式实际上一个匿名内部类
  • 所以我们的问题可以转向这两个问题:
    • 为什么匿名内部类调用外部引用的时候,外部引用需要用final修饰?
    • lamda如果才能修改外部引用变量?

1. 为什么匿名内部类调用外部引用的时候,外部引用需要用final修饰?

  • 我们在内部类中调用外部的自由变量,即使该变量没有显式的声明final,但是在编译器解析的时候也被定义成一个final变量
  • 这里java内部类引用外部变量近似闭包的概念。我们先来了解一下js中满足闭包的条件:
    1. 一个依赖于外部环境自由变量的函数
    2. 这个函数能够访问外部环境里的自由变量
  • 闭包常见使用场景
    1. 回调函数
    2. 匿名函数
  • 在闭包中访问外部自由变量访问的是自由变量的哪个值呢?
    • 是闭包定义时,自由变量所定义的值(非运行时!)
  • js中通常我们要解决闭包导致对象不正确问题,常用的有四个解决方案:
    1. func.call(obj, 20, 30)
    2. func.apply(obj, [20,30])
    3. const func1 = func.bind(obj,20,30)
    4. 在闭包外方法中手动指定 let self = this
  • 说到闭包,绕不开this指向问题,this应该指向的是运行时的对象,简单总结this指向三种情况:
    1. obj.func() -> this指向.前面调用的对象,此时指向obj
    2. new Fun() -> this指向new出来的对象
    3. 函数自调、匿名函数和回调函数 -> this指向的是window
  • java对闭包的处理
    1. 如函数在使用类的全局变量的时候
      • 全局变量实际是类的一个属性,用this指向,可所以修改
    2. 但是在处理匿名内部类的时候,在不同的类中无法用this指向,这时java的做法是:
      • 将自由变量拷贝一个副本带给匿名内部类,供内部类使用。
      • 类似于值传递而非引用传递

2. lamda如果才能修改外部引用变量?

  1. 数组
  2. 全局变量
  3. atomicReference

3. 划重点

lamda不能修改外部引用的变量的原因其实也很简单,本质上就是因为lambda表达式在方法内部,那么lambda表达式的内存分配就是在栈上。栈内存不存在线程安全问题,因为栈内存存的都是变量的副本。
对于局部变量count而言,它的生命周期就是所在方法的生命周期。这就决定了count无法被位于同一个栈帧上的lambda修改,因为这种修改毫无意义,
你无法将你的修改传递出当前栈帧。栈内存不会被共享,也就意味着你没有权利和其他栈帧通信。

如果非要在lambda内部修改lambda表达式外部的局部变量的值呢?
有两种方式:使用数组或者把局部变量定义为全局变量。

这2种方式,其实本质是一样的:内存都分配在堆上。这就决定了,使用这2种方式来修改变量的值,是可行的。

转载请注明出处:www.meidanlong

你可能感兴趣的:(问题解决,lambda,java)