美文网首页
java(final和lambda表达式)

java(final和lambda表达式)

作者: luckee | 来源:发表于2019-01-18 13:36 被阅读0次

    final修饰类表示该类不能被继承,final修饰方法表示该方法不能被重写(override),final修饰变量表示该变量一旦被赋值后就不能再被修改。要说的是第三种情况。使用lambda表达式(还有匿名内部类,两者本质相同,注意lambda表达式只能用于函数式接口)要求使用的外层局部变量必须是final修饰的(如果不显式的声明为final,则不允许出现修改该局部变量的操作,即隐式的final),从java内存分配我们知道,final修饰的变量是放在方法区的,这就是关键。

    image.png
    java8带来很多新的特性,引入lambda表达式是为了加入函数式编程风格,虽然我对函数式,闭包,回调函数这些弄不灵清,但没有关系,我们依然可以分析出为什么引用外层局部变量必须是final修饰的。首先我提出两个概念,我们知道,变量有作用域,但我想分的更细一点,分为空间域和时间域(其实就是生命周期)。空间域由{}决定,变量只在定义它的代码块范围内可见。时间域由方法是否执行完成决定,一个方法内的定义的变量(形参实际上也是方法内部定义的变量,只不过是隐式的,每个方法调用的时候会在方法内定义形参,并把实参的值赋给形参),当方法在执行的时候,它就是存活的,方法结束了,这些变量就被销毁了。但是final修饰的就不一样,final变量存在于方法区,就算定义final变量的那个方法结束了,final变量并不会随着销毁。现在我们讲讲lambda表达式(和匿名内部类),lambda表达式实际上是一个方法,但是这个方法有点特别,它不是传进去就立即执行的,什么时候执行取决于你把方法传给谁,也就是执行时间不确定。我先举一个例子,在方法A内定义Int a = 100,然后方法A内执行给一个定时器(用定时器举例实际代码层面不能实现,因为lambda表达式只能用于函数式接口,而TimerTask不是,我这里用定时器举例只是为了说明问题)对象添加任务,任务的内容是24小时后打印a,然后方法A就结束。我们来分析一下,当我们给定时器传入“打印a”的任务时,我们只是预定了一段代码的执行,预定的代码并不立即执行。24小时后,预定的代码开始执行,来打印a的时候,发现a早就不存在了(A方法结束后a就别销毁了),所以会报错。但是如果使用final修饰a,a就不会随着A的结束而被销毁,而是一直保存在方法区内,就能顺利地执行打印a的代码了。方法区存放的数据为.class文件的内容,静态变量,final变量和即时编译的代码(编译器将一些热点代码直接从源码编译成机器码),可以看到方法区中的数据都是不怎么会变化的数据,所以不是gc重点关注的JVM内存区域,gc重点关注的JVM内存区域是堆

    相关文章

      网友评论

          本文标题:java(final和lambda表达式)

          本文链接:https://www.haomeiwen.com/subject/nekndqtx.html