Недавно я столкнулся с сообщением об ошибке "Пустое конечное поле obj, возможно, не было инициализировано".
Обычно это происходит, если вы попытаетесь обратиться к полю, которое еще не присвоено значению. Пример класса:
public class Foo {
private final Object obj;
public Foo() {
obj.toString(); // error (1)
obj = new Object();
obj.toString(); // just fine (2)
}
}
Я использую Eclipse. В строке (1)
я получаю ошибку, в строке (2)
все работает. Пока что имеет смысл.
Затем я пытаюсь получить доступ к obj
в анонимном интерфейсе, который я создаю внутри конструктора.
public class Foo {
private Object obj;
public Foo() {
Runnable run = new Runnable() {
public void run() {
obj.toString(); // works fine
}
};
obj = new Object();
obj.toString(); // works too
}
}
Это тоже работает, поскольку я не получаю доступ к obj
в момент создания интерфейса. Я мог бы передать мой экземпляр в другое место, затем инициализировать объект obj
, а затем запустить мой интерфейс. (Однако было бы целесообразно проверить null
перед его использованием). Все еще имеет смысл.
Но теперь я сокращаю создание моего экземпляра Runnable
до версии гамбургера с помощью выражения лямбда:
public class Foo {
private final Object obj;
public Foo() {
Runnable run = () -> {
obj.toString(); // error
};
obj = new Object();
obj.toString(); // works again
}
}
И вот здесь я больше не могу следовать. Здесь я снова получаю предупреждение. Я знаю, что компилятор не обрабатывает лямбда-выражения как обычные инициализации, он не "заменяет его на длинную версию". Однако почему это влияет на то, что я не запускаю часть кода в моем методе run()
во время создания объекта Runnable
? Я все еще могу выполнить инициализацию, прежде чем я вызову run()
. Таким образом, технически можно встретить NullPointerException
здесь. (Хотя было бы лучше проверить и на null
здесь, но это соглашение - еще одна тема.)
Какую ошибку я делаю? Что такое lambda по-разному, что влияет на мое использование объекта так, как оно есть?
Я благодарю вас за дальнейшие объяснения.