我正在使用Java 8中的lambda表达式,并遇到警告本地变量从lambda表达式引用必须是final或有效 final
。我知道当我在匿名类中使用变量时,它们必须在外部类中是final的,但仍然存在问题-什么是final和有效final之间的区别?
我正在使用Java 8中的lambda表达式,并遇到警告本地变量从lambda表达式引用必须是final或有效 final
。我知道当我在匿名类中使用变量时,它们必须在外部类中是final的,但仍然存在问题-什么是final和有效final之间的区别?
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;
}
...
}
...
}
http://codeinventions.blogspot.in/2014/07/difference-between-final-and.html
http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html
numberLength
成为该方法的局部变量。 - mykola我认为解释“ effectively final ”最简单的方法是想象在变量声明中添加 final
修饰符。 如果进行此更改,程序在编译时和运行时继续以相同的方式工作,则该变量就是 effectively final。
case k
需要一个_常量表达式_,它可以是_常量变量_(“常量变量是使用常量表达式初始化的原始类型或String类型的final变量”[JLS 4.12.4](https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.12.4)),这是final变量的一种特殊情况。 - Colin D Bennett下面这个变量是final的,一旦初始化后我们就无法改变它的值。如果我们试图修改,将会出现编译错误...
final int variable = 123;
但是,如果我们像这样创建一个变量,就可以改变它的值...
int variable = 123;
variable = 456;
然而在Java 8中,默认情况下所有的变量都是final的,但代码中第二行的存在使其成为非 final的。因此,如果我们从上述代码中删除第二行,则该变量现在是"有效 final"的...
int variable = 123;
所以.. 任何只被赋值一次的变量,都被视为“有效地是final的”.
一个在初始化后值从未改变的变量或参数被视为有效的 final。
基本上,如果编译器发现一个变量在其初始化之外没有出现赋值操作,则该变量被视为有效的 final。
例如,考虑以下类:
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;
}
}
bar
是一个参数,而不是一个字段。 - peter.petrov'Effectively final'是指一个变量在没有被标注为final的情况下,也不会给编译器造成错误。
来自'Brian Goetz'的文章,
非正式地说,如果一个局部变量的初始值从未改变,则其“有效地”为final——换句话说,声明它为final不会导致编译失败。
当一个变量在其所属的类中被初始化一次且从未被修改时,它被称为final或有效地final。而且我们不能在循环或内部类中初始化它。
Final:
final int number;
number = 23;
有效的终态:
int number;
number = 34;
注意:最终值和有效最终值非常相似(它们在赋值后的值不会改变),只是有效最终变量没有使用关键字
final
进行声明。
@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;
};
}
}
Effective final主题在JLS 4.12.4中有描述,最后一段提供了清晰的解释:
如果变量是有效的final,那么在其声明中添加final修饰符不会引入任何编译时错误。相反,如果一个局部变量或参数在有效程序中被声明为final,那么如果去除final修饰符,它将成为有效的final。
final是使用关键字final
声明的变量,例如:
final double pi = 3.14 ;
在整个程序中它是不可变的,不能在此行之后更改pi。
有效地 final: 任何只被赋值一次或者只更新一次的局部变量或参数。它可能不会在整个程序中保持有效地 final。因此,这意味着有效地 final变量在至少进行一次分配/更新之后立即失去了其有效地 final属性。例子:
class EffectivelyFinal {
public static void main(String[] args) {
calculate(124,53);
}
public static void calculate( int operand1, int operand2){
int rem = 0; // operand1, operand2 and rem are effectively final here
rem = operand1%2 // rem lost its effectively final property here because it gets its second assignment
// operand1, operand2 are still effectively final here
class operators{
void setNum(){
operand1 = operand2%2; // operand1 lost its effectively final property here because it gets its second assignment
}
int add(){
return rem + operand2; // does not compile because rem is not effectively final
}
int multiply(){
return rem * operand1; // does not compile because both rem and operand1 are not effectively final
}
}
}
}
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;
}
}
}