Java 最终和有效最终之间的区别
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20938095/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Difference between final and effectively final
提问by alex
I'm playing with lambdas in Java 8 and I came across warning local variables referenced from a lambda expression must be final or effectively final
. I know that when I use variables inside anonymous class they must be final in outer class, but still - what is the difference between finaland effectively final?
我在 Java 8 中使用 lambdas 并且遇到了 warning local variables referenced from a lambda expression must be final or effectively final
。我知道当我在匿名类中使用变量时,它们在外部类中必须是 final 的,但仍然 - final和有效 final之间有什么区别?
采纳答案by Suresh Atta
... starting in Java SE 8, a local class can access local variables and parameters of the enclosing block that are final or effectively final. A variable or parameter whose value is never changed after it is initialized is effectively final.
...从 Java SE 8 开始,本地类可以访问最终或有效最终的封闭块的局部变量和参数。其值在初始化后永远不会改变的变量或参数实际上是最终的。
For example, suppose that the variable numberLength
is not declared final, and you add the marked assignment statement in the PhoneNumber
constructor:
例如,假设变量numberLength
未声明为 final,并且您在PhoneNumber
构造函数中添加了标记的赋值语句:
public class OutterClass {
int numberLength; // <== not *final*
class PhoneNumber {
PhoneNumber(String phoneNumber) {
numberLength = 7; // <== assignment to numberLength
String currentNumber = phoneNumber.replaceAll(
regularExpression, "");
if (currentNumber.length() == numberLength)
formattedPhoneNumber = currentNumber;
else
formattedPhoneNumber = null;
}
...
}
...
}
Because of this assignment statement, the variable numberLength is not effectively final anymore. As a result, the Java compiler generates an error message similar to "local variables referenced from an inner class must be final or effectively final"where the inner class PhoneNumber tries to access the numberLength variable:
由于这个赋值语句,变量 numberLength 不再有效。因此,Java 编译器会生成类似于“从内部类引用的局部变量必须是最终的或有效的最终”的错误消息,其中内部类 PhoneNumber 尝试访问 numberLength 变量:
http://codeinventions.blogspot.in/2014/07/difference-between-final-and.html
http://codeinventions.blogspot.in/2014/07/difference-between-final-and.html
http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html
http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html
回答by Mark Elliot
According to the docs:
根据文档:
A variable or parameter whose value is never changed after it is initialized is effectively final.
其值在初始化后永远不会改变的变量或参数实际上是最终的。
Basically, if the compiler finds a variable does not appear in assignments outside of its initialization, then the variable is considered effectively final.
基本上,如果编译器发现一个变量没有出现在其初始化之外的赋值中,那么该变量被认为是有效的 final。
For example, consider some class:
例如,考虑一些类:
public class Foo {
public void baz(int bar) {
// While the next line is commented, bar is effectively final
// and while it is uncommented, the assignment means it is not
// effectively final.
// bar = 2;
}
}
回答by Girish
public class LambdaScopeTest {
public int x = 0;
class FirstLevel {
public int x = 1;
void methodInFirstLevel(int x) {
// The following statement causes the compiler to generate
// the error "local variables referenced from a lambda expression
// must be final or effectively final" in statement A:
//
// x = 99;
}
}
}
As others have said, a variable or parameter whose value is never changed after it is initialized is effectively final. In the above code, if you change the value of x
in inner class FirstLevel
then the compiler will give you the error message:
正如其他人所说,一个变量或参数的值在它初始化后永远不会改变是有效的。在上面的代码中,如果你改变x
内部类中的值,FirstLevel
那么编译器会给你错误信息:
Local variables referenced from a lambda expression must be final or effectively final.
从 lambda 表达式引用的局部变量必须是最终的或有效的最终变量。
回答by Maurice Naftalin
I find the simplest way to explain "effectively final" is to imagine adding the final
modifier to a variable declaration. If, with this change, the program continues to behave in the same way, both at compile time and at run time, then that variable is effectively final.
我发现解释“有效最终”的最简单方法是想象将final
修饰符添加到变量声明中。如果通过这种更改,程序在编译时和运行时继续以相同的方式运行,那么该变量实际上是最终的。
回答by FiruzzZ
However, starting in Java SE 8, a local class can access local variables and parameters of the >enclosing block that are final or effectively final.
但是,从 Java SE 8 开始,局部类可以访问局部变量和 > 封闭块的最终或有效最终的参数。
This didn't start on Java 8, I use this since long time. This code used (before java 8) to be legal:
这不是从 Java 8 开始的,我使用它很久了。此代码使用(在 java 8 之前)是合法的:
String str = ""; //<-- not accesible from anonymous classes implementation
final String strFin = ""; //<-- accesible
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String ann = str; // <---- error, must be final (IDE's gives the hint);
String ann = strFin; // <---- legal;
String str = "legal statement on java 7,"
+"Java 8 doesn't allow this, it thinks that I'm trying to use the str declared before the anonymous impl.";
//we are forced to use another name than str
}
);
回答by infoj
When a lambda expression uses an assigned local variable from its enclosing space there is an important restriction. A lambda expression may only use local variable whose value doesn't change. That restriction is referred as "variable capture" which is described as; lambda expression capture values, not variables.
The local variables that a lambda expression may use are known as "effectively final".
An effectively final variable is one whose value does not change after it is first assigned. There is no need to explicitly declare such a variable as final, although doing so would not be an error.
Let's see it with an example, we have a local variable i which is initialized with the value 7, with in the lambda expression we are trying to change that value by assigning a new value to i. This will result in compiler error - "Local variable i defined in an enclosing scope must be final or effectively final"
当 lambda 表达式使用其封闭空间中已分配的局部变量时,有一个重要的限制。一个 lambda 表达式只能使用其值不会改变的局部变量。该限制被称为“变量捕获”,描述为;lambda 表达式捕获值,而不是变量。
lambda 表达式可能使用的局部变量被称为“有效最终”。
一个有效的最终变量是一个在第一次赋值后其值不会改变的变量。无需将此类变量显式声明为 final,尽管这样做不会出错。
让我们看一个例子,我们有一个局部变量 i,它被初始化为值 7,在 lambda 表达式中,我们试图通过为 i 分配一个新值来更改该值。这将导致编译器错误 - “我在封闭范围内定义的局部变量必须是最终的或有效的最终”
@FunctionalInterface
interface IFuncInt {
int func(int num1, int num2);
public String toString();
}
public class LambdaVarDemo {
public static void main(String[] args){
int i = 7;
IFuncInt funcInt = (num1, num2) -> {
i = num1 + num2;
return i;
};
}
}
回答by Ajeet Ganga
'Effectively final' is a variable which would not give compiler error if it were to be appended by 'final'
'Effectively final' 是一个变量,如果它被 'final' 附加,它不会给编译器错误
From a article by 'Brian Goetz',
来自'Brian Goetz'的一篇文章,
Informally, a local variable is effectively final if its initial value is never changed -- in other words, declaring it final would not cause a compilation failure.
非正式地,如果局部变量的初始值从未改变,则它实际上是 final 的——换句话说,将其声明为 final 不会导致编译失败。
回答by samadadi
A variable is finalor effectively finalwhen it's initialized onceand it's never mutatedin its owner class. And we can't initializeit in loopsor inner classes.
当一个变量被初始化一次并且它在它的所有者类中永远不会发生变异时,它就是最终的或有效的最终变量。我们不能在循环或内部类中初始化它。
Final:
决赛:
final int number;
number = 23;
Effectively Final:
有效最终:
int number;
number = 34;
Note: Finaland Effective Finalare similar(Their value don't change after assignment) but just that effective Final variables are not declared with Keyword
final
.
注意:Final和Effective Final类似(赋值后它们的值不会改变),只是有效的 Final 变量没有用 Keyword 声明
final
。
回答by Eurig Jones
This variable below is final, so we can't change it's value once initialised. If we try to we'll get a compilation error...
下面的这个变量是final,所以一旦初始化我们就不能改变它的值。如果我们尝试,我们会得到一个编译错误......
final int variable = 123;
But if we create a variable like this, we can change it's value...
但是如果我们创建一个这样的变量,我们可以改变它的值......
int variable = 123;
variable = 456;
But in Java 8, all variables are finalby default. But the existence of the 2nd line in the code makes it non-final. So if we remove the 2nd line from the above code, our variable is now "effectively final"...
但是在Java 8 中,默认情况下所有变量都是final的。但是代码中第二行的存在使它成为non-final。所以如果我们从上面的代码中删除第二行,我们的变量现在是“有效最终的”......
int variable = 123;
So.. Any variable that is assigned once and only once, is "effectively final".
所以..任何被分配一次且仅一次的变量是“有效最终的”。
回答by snr
If you could add the
final
modifier to a local variable, it was effectively final.
如果您可以将
final
修饰符添加到局部变量,则它实际上是 最终的。
Lambda expressions can access
Lambda 表达式可以访问
static variables,
instance variables,
effectively final method parameters, and
effectively final local variables.
静态变量,
实例变量,
有效的最终方法参数,和
有效地最终局部变量。
来源:OCP:Oracle Certified Professional Java SE 8 Programmer II 学习指南,Jeanne Boyarsky、Scott Selikoff
Additionally,
此外,
An
effectively final
variable is a variable whose value is never changed, but it isn't declared with thefinal
keyword.
一个
effectively final
变量是一个变量,其值永远不会改变,但它不与声明的final
关键字。
Source: Starting Out with Java: From Control Structures through Objects (6th Edition), Tony Gaddis
来源:从 Java 开始:从控制结构到对象(第 6 版),Tony Gaddis
Furthermore, don't forget the meaning of final
that it is initialized exactly once before it is used for the first time.
此外,不要忘记final
它在第一次使用之前只初始化一次的含义。