Оценка выражений в ссылках на методы Java во время выполнения

В разделе Оценка времени выполнения Ссылки на методы Спецификации языка Java упоминается, что:

Во время выполнения оценка выражения ссылки на метод аналогична оценке выражения создания экземпляра класса, поскольку обычное завершение создает ссылку на объект. Оценка выражения ссылки на метод отличается от вызова самого метода.

Во-первых, если выражение ссылки на метод начинается с ExpressionName или Primary, оценивается это подвыражение. Если подвыражение оценивается как null, возникает NullPointerException, и выражение ссылки на метод завершается внезапно. Если подвыражение завершается внезапно, выражение ссылки на метод завершается внезапно по той же причине.

И ExpressionName и Primary определены в синтаксис выражения ссылки на метод:

MethodReference:
  ExpressionName :: [TypeArguments] Identifier
  ReferenceType :: [TypeArguments] Identifier
  Primary :: [TypeArguments] Identifier
  super :: [TypeArguments] Identifier
  TypeName . super :: [TypeArguments] Identifier
  ClassType :: [TypeArguments] new
  ArrayType :: new 

Меня заинтересовала выделенная часть, и я хотел протестировать упомянутое поведение, используя приведенный ниже код:

public class Test {

    public static void main(String[] args) {
        System.out.println("Testing...");
        final Person p = null;
        foo(p::getName); // I was expecting an NPE here
    }

    private static void foo(Supplier<String> supplier) {
        System.out.println(supplier);

        // supplier.get();  // uncommenting this causes an NPE, but not when evaluating
                            // the method reference, but rather when the method is invoked.
    }

    static class Person {
        String getName() {
            return "x";
        }
    }
}

Однако строка foo(p::getName) не генерирует исключение NullPointerException. Я неправильно понимаю приведенную выше цитату из JLS? Если да, может ли кто-нибудь более подробно объяснить значение вышеприведенной цитаты или привести пример, где это могло бы произойти?


person M A    schedule 14.12.2017    source источник
comment
интересно, я ожидал, что это действительно вызовет исключение, и я попытался изменить его на лямбда-выражение (думая, что это наверняка сломается), но этого не произошло. хороший вопрос   -  person Eugene    schedule 14.12.2017
comment
Я согласен, согласно спецификации, ссылка на метод p::getName должна была вызвать NPE. Думаю, они не добавляли эту проверку, поэтому NPE откладывается до фактического использования. См. Соответствующий JDK-8131323.   -  person Andreas    schedule 14.12.2017
comment
Есть более ранний вопрос по этому поводу, однако там нет ссылки на отчет в системе отслеживания ошибок Eclipse. Я не сомневаюсь, я видел такое в прошлом ...   -  person Holger    schedule 14.12.2017
comment
@Holger отличная находка - значит, это дубликат, я думаю   -  person Eugene    schedule 14.12.2017
comment
bugs.eclipse.org/bugs/show_bug.cgi?id=521182   -  person Holger    schedule 14.12.2017
comment
@Holger Я как раз собирался создать новую ошибку :) Спасибо за полезную ссылку.   -  person M A    schedule 14.12.2017


Ответы (1)


Ох, блин! Это ошибка затмения (ECJ), она не работает с javac/java (I ' я пробовал 9 здесь, в примере, но то же самое происходит в 8):

 Testing...
 Exception in thread "main" java.lang.NullPointerException
 at java.base/java.util.Objects.requireNonNull(Objects.java:221)
 at org.eugene.so.DeleteMe.main(DeleteMe.java:11)
person Eugene    schedule 14.12.2017
comment
Согласно JDK-8131323, вы больше не получаете NPE с jdk 8 b119, несмотря на то, что ошибка закрыта как «Не проблема», учитывая, что спецификация требует NPE. - person Andreas; 14.12.2017
comment
@Andreas: «b119» относится к «beta 119» (обратите внимание на дату этого комментария). Хотя у меня под рукой нет бета-версии 119, я могу утверждать, что указанное поведение при вызове NPE проявляется в более поздних версиях, особенно во всех версиях выпуска; Самая ранняя версия, которая у меня есть для тестирования, - b132. Неясно, какую настройку использовал комментатор, но комментарий был добавлен, когда проблема уже была закрыта. - person Holger; 14.12.2017
comment
@Holger DOH! Я подумал u119, когда увидел это b119. - person Andreas; 14.12.2017