В главе о lambda expression bodies говорится
В отличие от кода появляются в объявлениях анонимных классов, смысл имен и this
и super
ключевые слова, входящие в лямбда тела, наряду с доступностью ссылочных деклараций, одинаковы как в окружении (за исключением того, что параметры лямбда вводят новых имен).
Прозрачность this
в теле выражения в лямбды (как явного и неявного) - то есть, рассматривая его так же, как и в окружающего контекста - обеспечивает большую гибкость для реализаций, и предотвращает значение неквалифицированного имена в теле от в зависимости от разрешения перегрузки.
Они более строгие из-за этого.
Окружающий контекст, в данном случае, является присвоением полю, а проблема под рукой - это доступ к полю, val
, пустое поле final
, в правой части выражения.
Спецификация языка Java утверждает
Каждая локальная переменная (§14.4) и каждое пустое поле final
(§4.12.4, §8.3.1.2) должны быть, безусловно, присвоенное значение, когда какой-либо доступ его Значение.
Доступ к ее значению состоит из простого имени переменной (или, для поля, простое имя поля правомочного по this
) происходит в любом месте в выражении, за исключением левого операнда простой оператор присваивания =
(§15.26.1).
Для каждого доступа к локальной переменной или пустой final
поле x
, x
должен быть определенно присвоенной перед въездом, или во время компиляции происходит ошибка.
Затем он продолжает говорить
Пусть C
быть классом, и пусть V
быть пустым final
не- static
элемент поля из C
, объявленная в C
. Тогда:
V
определенно Unassigned (и к тому же не обязательно назначается) до крайнего левого экземпляра инициализатора (§8.6) или переменного экземпляр инициализатора C
.
V
это [не] установленный перед экземпляром инициализатора или переменный экземпляром инициализатором C
отличных от крайней левой тогда и только тогда V
является [ип] установленный после предыдущего экземпляра инициализатора или экземпляра переменного инициализатора C
.
Ваш код в основном выглядит следующим образом
private final int val;
// leftmost instance variable initializer, val still unassigned
private final Callable<String> anonInnerGetValString = ...
// still unassigned after preceding variable initializer
private final Callable<String> lambdaGetValString = ...
поэтому компилятор определяет, что val
в Unassigned, когда это доступ в выражении инициализации для lambdaGetValString
.
Приведенные выше правила применяются к использованию простого имени, val
, а не к квалифицированному выражению, this.val
. Вы можете использовать
final Callable<String> lambdaGetValString =() -> String.valueOf(this.val);
Связанные: http://stackoverflow.com/questions/30130148/reference-to-the-final-field-from-lambda-expression –
Интересно, что если вы снимаете 'final' модификатор на 'val' он компилирует ... – lucasvw
Когда вы меняете' String.valueOf (val) 'на' String.valueOf (Immutable.this.val) 'он тоже компилируется – csharpfolk