Ссылка на последнее поле из лямбда-выражения
Недавно я обнаружил тонкую разницу между анонимным классом и лямбда-выражением:
public class FinalTest {
final Runnable x = new Runnable() {
@Override
public void run() {
System.out.println(x.hashCode());
}
};
final Runnable y = () -> System.out.println(y.hashCode());
}
Обычно лямбды эквивалентны анонимным классам. Даже моя Eclipse IDE имеет рефакторинг для преобразования x
лямбда (становится точно так же, как y
) и конвертировать y
в анонимный класс (это становится точно так же, как x
). Однако лямбда дает мне ошибку компиляции, в то время как анонимный класс может быть отлично скомпилирован. Сообщение об ошибке выглядит так:
>javac FinalTest.java
FinalTest.java:9: error: self-reference in initializer
final Runnable y = () -> System.out.println(y.hashCode());
^
1 error
Вопрос в том, почему такая разница?
1 ответ
Это связано с JLS #8.3.3, работающим с прямыми ссылками. В частности, если вы используете полностью определенное имя, оно компилируется (поскольку третье условие этого правила становится ложным . Использование - это простое имя в инициализаторе переменной экземпляра C или инициализаторе экземпляра C):
final Runnable y = () -> System.out.println(this.y.hashCode());
В случае анонимного класса четвертое условие (C является самым внутренним классом или интерфейсом, включающим использование) не выполняется, поскольку включающий класс является самим анонимным классом.