Я играю с лямбдами в Java 8 и наткнулся на предупреждение local variables referenced from a lambda expression must be final or effectively final. Я знаю, что когда я использую переменные внутри анонимного класса, они должны быть final во внешнем классе, но все же - в чем разница между final и effectively final?
Переведено автоматически
Ответ 1
... начиная с Java SE 8, локальный класс может обращаться к локальным переменным и параметрам окружающего блока, которые являются final или эффективно final . Переменная или параметр, значение которого никогда не изменяется после его инициализации, фактически является final.
Например, предположим, что переменная numberLength не объявлена final, и вы добавляете отмеченный оператор присваивания в PhoneNumber конструктор:
Из-за этого оператора присваивания переменная numberLength больше не является final . В результате компилятор Java генерирует сообщение об ошибке, подобное "локальные переменные, на которые ссылаются из внутреннего класса, должны быть final или эффективно final" где внутренний класс PhoneNumber пытается получить доступ к переменной numberLength:
Я считаю, что самый простой способ объяснить "effectively final" - это представить добавление модификатора final к объявлению переменной. Если после этого изменения программа продолжает вести себя таким же образом как во время компиляции, так и во время выполнения, то эта переменная фактически является final .
Ответ 3
Приведенная ниже переменная является final, поэтому мы не можем изменить ее значение после инициализации. Если мы попытаемся это сделать, то получим ошибку компиляции...
finalintvariable=123;
Но если мы создадим такую переменную, как эта, мы сможем изменить ее значение...
intvariable=123; variable = 456;
Но в Java 8 все переменные по умолчанию являются final. Но наличие 2-й строки в коде делает ее не окончательной. Итак, если мы удалим 2-ю строку из приведенного выше кода, наша переменная теперь будет "effectively final"...
intvariable=123;
Итак.. Любая переменная, которая назначается один и только один раз, является "effectively final".
Переменная или параметр, значение которого никогда не изменяется после его инициализации, фактически является final .
В принципе, если компилятор обнаруживает, что переменная не отображается в присваиваниях вне ее инициализации, то переменная считается эффективно final.
Например, рассмотрим некоторый класс:
publicclassFoo {
publicvoidbaz(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.