Java停止了内部类中非最终变量的错误(java 8)[重复]
Posted
技术标签:
【中文标题】Java停止了内部类中非最终变量的错误(java 8)[重复]【英文标题】:Java stopped erroring on non-final variables in inner classes (java 8) [duplicate] 【发布时间】:2015-04-09 02:16:04 【问题描述】:Java 7 在以下代码中说“不能引用在封闭范围内定义的非最终局部变量消息”:
public class Runner
public static void main(String[] args)
String message = "Hello world";
new Runnable()
@Override
public void run()
System.out.println(message);
.run();
Java 8 没有。
怀疑这是为了给 Java 添加函数式编程特性。
它是否类似地处理代码?
【问题讨论】:
【参考方案1】:Java 8 隐含地将 message
设为 final,因为它从未被修改过。尝试在代码中的任何地方修改它,你会得到一个编译错误(因为这会删除隐含的final
)。
这被称为实际上是最终的。引用From the docs:
但是,从 Java SE 8 开始,本地类可以访问封闭块的局部变量和参数,它们是最终的或有效的最终的。一个变量或参数,其值在初始化后永远不会改变,它实际上是最终的。
【讨论】:
只要在任何地方(Runnable 之外)修改它就会出现错误,对吧? 是的,没错。把它想象成一个看不见的final
。
Java 8:潜行 100
嗨,有没有办法在 java 8 中有效地禁用 final (或在编译时显示警告)?我想精确地写'final'以避免代码中的错误引用【参考方案2】:
Java 8(和 Lambdas)引入了 Effectively final 术语:即使您没有使用 final
关键字将其定义为 final,但如果不修改,它与 final 一样好.
引用Oracle Tutorial: Local Classes:
但是,从 Java SE 8 开始,本地类可以访问封闭块的局部变量和参数,它们是最终的或实际上是最终的。一个变量或参数,其值在初始化后永远不会改变,它实际上是最终的。
您的消息实际上是最终的,因此可以从匿名内部类和 lambda 中引用它。
如果您更改消息的值,它将不再是有效的最终:
String message = "Hello world";
new Runnable()
@Override
public void run()
System.out.println(message);
.run();
message = "modified";
因此您会收到以下错误(来自 Eclipse):
在封闭范围内定义的局部变量消息必须是最终的或有效的最终
或形成javac
:
错误:从内部类引用的局部变量必须是 final 或有效 final
【讨论】:
【参考方案3】:变量message
是effectively final。引用语言参考
如果一个变量实际上是 final 的,将 final 修饰符添加到它的 声明不会引入任何编译时错误。
因此,因为 message
引用在您的内部类中的任何地方都没有更改,所以编译器将其视为有效的 final。
这会引发错误:
new Runnable()
@Override
public void run()
message = "hey";
System.out.println(message);
.run();
java7 编译器抛出错误的原因是 lambdas 的规范更改。
使用的任何局部变量、形式参数或异常参数,但 不使用任何局部变量、形式参数或异常参数 但未在 lambda 表达式中声明的必须要么声明为 final 或有效地最终(§4.12.4),或发生编译时错误 尝试使用的地方。
匿名内部类和 lambda 共享相同的规则。
【讨论】:
【参考方案4】:是的,有点像。
基本上,他们意识到编译器已经必须通过分析代码来决定何时局部变量是“有效最终的”,也就是说,它的值永远不会改变。
所以语义没有改变:虽然不再需要显式声明变量 final
,但您仍然必须确保它永远不会被重新分配。
【讨论】:
只是附注:他们必须一直都知道——这与自那时以来一直产生final
相关的编译器错误的分析完全相同Java 1.0 :) 在此期间发生了变化的是 Java 的精神——曾经是一种“蓝领语言”,其中样板和冗长是 特性,今天是一种具有全面的 FP 支持和语法糖。
@MarkoTopolnik 你是对的,他们意识到更多的是他们可以单独依靠它,没有理由强迫开发人员添加final
关键字。但从第一天起,答案就一直盯着他们。以上是关于Java停止了内部类中非最终变量的错误(java 8)[重复]的主要内容,如果未能解决你的问题,请参考以下文章
Java之路 - final内部类ObjectDateCalendar