2017-12-14 259 views
8

w sekcji Run-Time Evaluation of Method References z języka Java Specification, wspomniano, że:Runtime oceny wyrażeń w metodzie Java odwołuje

W czasie wykonywania oceny wyrażenia referencyjnego metoda jest podobna do oceny z tworzenia instancji klasy wyrażenie, o ile zwykłe wypełnienie tworzy odniesienie do obiektu. Ocena wyrażenia referencyjnego metody różni się od wywołania samej metody.

pierwsze, jeśli ekspresja Referencyjny Sposób rozpoczyna się ExpressionName lub podstawowej to wyrażenie zostanie ocenione. Jeśli podwyrażenie zostanie ocenione na null, zostanie podniesiona wartość NullPointerException, a wyrażenie odwołania do metody zakończy się nagle. Jeśli podwyrażenie zakończy się nagle, wyrażenie referencyjne metody kończy się nagle z tego samego powodu.

I ExpressionName i Podstawowa są zdefiniowane w method reference expression syntax:

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

byłem zainteresowany przez podświetlonej części i chciał przetestować wspomniany zachowanie za pomocą poniższego kodu:

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"; 
     } 
    } 
} 

Jednak linia foo(p::getName) nie rzucać NullPointerException. Czy nie rozumiem powyższego cytatu z JLS? Jeśli tak, czy ktoś mógłby wyjaśnić więcej znaczenia powyższej oferty lub podać przykład, gdzie by to miało miejsce?

+1

interesujący, bym spodziewałem się rzucać rzeczywiście wyjątek i Próbuję zmienić go do wyrażenia lambda (myśląc, że to na pewno się zepsuje), ale tak się nie stało. dobre pytanie – Eugene

+0

Zgadzam się, zgodnie ze specyfikacją, odwołanie do metody 'p :: getName' powinno zawierać NPE. Zgadnij, że nie dodali tej walidacji, więc NPE jest odroczone do momentu rzeczywistego użycia. Zobacz powiązane [JDK-8131323] (https://bugs.openjdk.java.net/browse/JDK-8131323). – Andreas

+1

Istnieje [wcześniejsze pytanie na ten temat] (https://stackoverflow.com/q/37681625/2711488), jednak brak odnośnika do raportu w narzędziu do śledzenia błędów Eclipse. Jestem cicho pewien, widziałem jeden w przeszłości ... – Holger

Odpowiedz

7

O cholera! To eclipse bug (ECJ), nie jest on z javac/java (Próbowałem 9 tutaj na przykład, ale to samo dzieje się w 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) 
+1

Zgodnie z [JDK-8131323] (https://bugs.openjdk.java.net/browse/JDK-8131323), nie masz już NPE z jdk 8 b119, mimo że błąd jest zamknięty jako "Not an Issue", biorąc pod uwagę wywołania spec dla NPE. – Andreas

+5

@Andreas: "b119" odnosi się do "beta 119" (zwróć uwagę na datę tego komentarza). Chociaż nie mam pod ręką wersji beta 119, mogę stwierdzić, że określone zachowanie rzucania NPE jest pokazane w późniejszych wersjach, szczególnie we wszystkich wersjach wydania; najwcześniejszą wersją, którą tu przetestowałem, jest b132. Nie jest jasne, z której konfiguracji korzystał komentator, ale komentarz został dodany, gdy problem został już zamknięty. – Holger

+1

@Holger DOH! Czy myślałem "U119", kiedy zobaczyłem, że 'b119'. – Andreas