Недавно я столкнулся с еще одним NullPointerException
в Java. Мне потребовалось довольно много времени, чтобы понять это, но в конце концов я нашел проблему.
Вот в чем дело: это ссылка на метод Java 8, которая вызывает исключение.
Когда я преобразовываю тот же самый фрагмент кода в лямбда-абстракцию, все работает просто отлично.
Мне удалось разбить его на этот SSCCE:
import java.util.function.Consumer;
public class Main{
public static void main(String[] args) {
Bar bar = new Bar(System.out::println);
Baz baz = new Baz(System.out::println);
bar.fooYou();
baz.fooYou();
}
}
abstract class Foo {
Consumer<String> fooConsumer;
Foo() {
fooConsumer = createConsumer();
}
void fooYou() {
fooConsumer.accept("foo yay!");
}
abstract Consumer<String> createConsumer();
}
class Bar extends Foo {
final Consumer<String> barConsumer;
Bar(Consumer<String> c) {
barConsumer = c;
}
@Override
Consumer<String> createConsumer() {
return t -> barConsumer.accept(t);
}
}
class Baz extends Foo {
final Consumer<String> bazConsumer;
Baz(Consumer<String> c) {
bazConsumer = c;
}
@Override
Consumer<String> createConsumer() {
return bazConsumer::accept;
}
}
Это приводит к "foo yay!", за которым следует исключение.
Это означает, что класс Bar работает нормально. Однако Баз терпит неудачу.
Я прочитал, но не до конца понял спецификации по адресу Оценка ссылок на методы во время выполнения, и я чувствую, что решение должно быть где-то там.
Кто-нибудь знает, в чем разница между лямбдой и ссылкой на метод относительно нулевых значений и т. д.?
Надеюсь найдутся специалисты, которые смогут мне помочь. Ошибка была слишком раздражающей, чтобы не узнать точное поведение Java 8. Заранее спасибо!
PS: После прочтения спецификаций я действительно подумал, что ни один из Bar, Baz не должен работать. Так почему один..?
createConsumer
происходит до того, как будет назначеноbazConsumer
, потому что это происходит в конструкторе суперкласса, поэтомуbazConsumer
становитсяnull
в тот момент, когда вы выполняетеbazConsumer::accept
. После этого это то же самое, что и ответ на связанный вопрос. (Кстати, я думаю, что ваш пример кода лучше, чем другой вопрос, но да, это сайт.) - person Radiodef   schedule 18.03.2018Bar
, поэтому неквалифицированныйbarConsumer
совпадает сBar.this.barConsumer
. Здесь обсуждается в спецификации. С другой стороны, ссылка на метод фиксирует экземплярbazConsumer
только во время оценки выражения ссылки на метод. - person Radiodef   schedule 18.03.2018static class Mapper { public int map(int i) { return i; } }
private static Mapper getMapper() { return null; }
и использованиеStream.of(1).map(getMapper()::map);
Обратите внимание, что нет терминальной операции, а это означает, что ничего не делается; это по-прежнему выдаетNullPointerException
, а это, с другой стороны,Stream.of(1).map(x -> getMapper().map(x));
не будет - person Eugene   schedule 18.03.2018