... начиная с Java SE 8, локальный класс может обращаться к локальным переменным и параметрам закрывающего блока, которые являются окончательными или фактически окончательными. Параметр или параметр, значение которого никогда не изменяется после его инициализации, фактически является окончательным.
blockquote>Например, предположим, что переменная
numberLength
не объявлена окончательной, и вы добавляете отмеченную инструкцию присваивания в конструкторе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; } ... } ... }
Из-за этого оператора присваивания переменная numberLength не является окончательной окончательной. В результате компилятор Java генерирует сообщение об ошибке, аналогичное «локальные переменные, на которые ссылается внутренний класс, должен быть окончательным или фактически окончательным», где внутренний класс PhoneNumber пытается получить доступ к переменной numberLength:
http://codeinventions.blogspot.in/2014/07/difference-between-final-and.html
http://docs.oracle.com/javase/tutorial /java/javaOO/localclasses.html
Согласно docs :
Измененная или параметр, значение которой никогда не изменяется после его инициализации, фактически является окончательным.
blockquote>В принципе, если компилятор обнаруживает, что переменная не появляется в назначениях за пределами ее инициализации, то переменная считается эффектно окончательной .
Например, рассмотрим некоторый класс:
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
в вашем примере не является локальной переменной, а полем. & quot; Эффективно окончательный & quot; в сообщении об ошибке, как указано выше, вообще не применяется к полям.
– Antti Haapala
1 January 2015 в 19:47
Из статьи 'Brian Goetz',
'Эффективно final' - это переменная, которая не выдавала бы ошибку компилятора, если бы она была добавлена 'final'
< / blockquote>
Когда в выражении лямбда используется назначенная локальная переменная из ее вмещающего пространства, существует важное ограничение. В выражении лямбда может использоваться только локальная переменная, значение которой не изменяется. Это ограничение упоминается как «захват переменной», который описывается как; значения захвата выражения лямбда, а не переменные . Локальные переменные, которые могут использовать выражение лямбда, известны как «эффективно окончательные». Эффективно конечная переменная - это значение, значение которого не изменяется после его первого назначения. Нет необходимости явно объявлять такую переменную как final, хотя делать это не будет ошибкой. Давайте посмотрим на пример, у нас есть локальная переменная i, которая инициализируется значением 7, причем в выражении лямбда мы пытаемся изменить это значение, назначив новое значение i. Это приведет к ошибке компилятора - « Локальная переменная 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;
};
}
}
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;
}
}
}
Как говорили другие, переменная или параметр, значение которого никогда не изменяется после его инициализации, фактически является окончательным. В приведенном выше коде, если вы измените значение x
во внутреннем классе FirstLevel
, компилятор выдаст вам сообщение об ошибке:
Локальные переменные, на которые ссылается выражение лямбда, должны быть окончательными или эффективно окончательный.
blockquote>
Эффективная окончательная тема описана в JLS 4.12.4 , а последний абзац содержит ясное объяснение:
Если переменная окончательно, добавив окончательный модификатор к его объявлению, не будет вводить какие-либо ошибки времени компиляции. И наоборот, локальная переменная или параметр, объявленный окончательно в действительной программе, становится фактически окончательным, если последний модификатор удален.
blockquote>
Эта переменная ниже окончательна, поэтому мы не можем изменить ее значение после инициализации. Если мы попытаемся получить ошибку компиляции ...
final int variable = 123;
Но если мы создадим такую переменную, мы можем изменить ее значение ...
int variable = 123;
variable = 456;
Но в Java 8 все переменные по умолчанию окончательны. Но наличие второй строки в коде делает ее не финальной. Поэтому, если мы удаляем вторую строку из приведенного выше кода, наша переменная теперь «эффективно финальная» ...
int variable = 123;
Итак. Любая переменная, которая назначается один раз и только один раз, является «фактически окончательной ».
Однако, начиная с Java SE 8, локальный класс может обращаться к локальным переменным и параметрам> закрывающего блока, которые являются окончательными или фактически окончательными.
blockquote>Это не начать с 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 } );
final
, но в Java 8 также i> те, что эффективно i> final.
– Antti Haapala
1 January 2015 в 19:33
Я считаю, что самый простой способ объяснить «эффективно окончательный» - представить себе добавление модификатора final
в объявление переменной. Если при этом изменении программа продолжает вести себя одинаково, как во время компиляции, так и во время выполнения, эта переменная является фактически окончательной.
case k
требуется выражение константа i>, которое может быть константой константой i> («Постоянная переменная является конечной переменной примитивного типа или типа String, которая инициализирована с постоянным выражением «g0] JLS 4.12.4 ), который является частным случаем конечной переменной.
– Colin D Bennett
3 April 2018 в 19:00
Переменная является окончательной или фактически окончательной, когда она инициализируется один раз, и она никогда не мутируется в классе владельца. И мы не можем инициализировать его в циклах или внутренних классах.
Final:
final int number;
number = 23;
Эффективно Final:
int number;
number = 34;
Если вы могли бы добавить модификатор
blockquote>final
к локальной переменной, это было эффективно окончательным.Лямбда-выражения могут получить доступ к
- статические переменные,
- переменные экземпляра,
- эффективные параметры окончательного метода и
- эффективно конечные локальные переменные.
Кроме того,
Переменная
blockquote>effectively final
- это переменная, значение которой никогда не изменяется, но не объявляется с ключевым словомfinal
.Источник: Запуск с Java: Из управляющих структур через объекты (6-е издание), Тони Гаддис
Кроме того, не забудьте значение
final
, что оно инициализируется ровно один раз, прежде чем оно будет использоваться в первый раз.