2017-12-14 110 views
8

Trong phần Run-Time Evaluation of Method References của ngôn ngữ Java Specification, nó được đề cập rằng:Runtime đánh giá biểu thức trong phương pháp Java tham chiếu

Vào lúc chạy, đánh giá của một biểu thức phương pháp tham chiếu là tương tự như đánh giá của một tạo lớp dụ biểu thức, trong khi hoàn thành bình thường tạo ra một tham chiếu đến một đối tượng. Việc đánh giá biểu thức tham chiếu phương thức khác biệt với việc gọi phương thức của chính nó.

Đầu tiên, nếu biểu thức tham chiếu phương thức bắt đầu bằng ExpressionName hoặc Primary, biểu thức con này được đánh giá. Nếu biểu thức con đánh giá là null, số NullPointerException được nâng lên và biểu thức tham chiếu phương thức hoàn thành đột ngột. Nếu biểu thức con hoàn thành đột ngột, biểu thức tham chiếu phương thức hoàn thành đột ngột vì cùng một lý do.

ExpressionNameTiểu được định nghĩa trong 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 

Tôi đã quan tâm bởi một phần tô đậm và muốn kiểm tra hành vi được đề cập bằng cách sử dụng mã bên dưới:

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

Tuy nhiên, dòng foo(p::getName) không ném NullPointerException. Tôi có hiểu sai câu nói trên từ JLS không? Nếu có, ai đó có thể giải thích thêm ý nghĩa của câu nói trên hoặc đưa ra một ví dụ mà nó sẽ xảy ra?

+1

thú vị, tôi sẽ mong nó để ném ngoại lệ thực sự và tôi đã cố gắng thay đổi nó đến một biểu thức lambda (nghĩ rằng điều này chắc chắn sẽ phá vỡ), nhưng nó không. Câu hỏi hay – Eugene

+0

Tôi đồng ý, theo thông số kỹ thuật, tham chiếu phương thức 'p :: getName' nên đã ném NPE. Đoán rằng họ đã không thêm xác nhận đó, vì vậy NPE được hoãn lại cho đến khi thực sự được sử dụng. Xem liên quan [JDK-8131323] (https://bugs.openjdk.java.net/browse/JDK-8131323). – Andreas

+1

Có một [câu hỏi trước đó về nó] (https://stackoverflow.com/q/37681625/2711488), tuy nhiên, không có liên kết đến một báo cáo trong trình theo dõi lỗi Eclipse ở đó. Tôi yên tĩnh chắc chắn, tôi đã thấy một trong quá khứ… – Holger

Trả lời

7

Oh darn! Đó là một eclipse bug (ECJ), nó không thành công với javac/java (Tôi đã thử 9 tới đây trong ví dụ này, nhưng điều tương tự xảy ra trong 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

Theo [JDK-8131323] (https://bugs.openjdk.java.net/browse/JDK-8131323), bạn không còn nhận được NPE với jdk 8 b119, mặc dù lỗi được đóng là "Không phải là vấn đề", cho các cuộc gọi spec cho NPE. – Andreas

+5

@Andreas: “b119” đề cập đến “beta 119” (lưu ý ngày của nhận xét đó). Mặc dù tôi không có beta 119 trong tay, tôi có thể khẳng định rằng hành vi được chỉ định khi ném NPE được hiển thị bởi các phiên bản sau, đặc biệt là tất cả các phiên bản phát hành; phiên bản đầu tiên tôi có ở đây để thử nghiệm là b132. Không rõ ràng, thiết lập người nhận xét được sử dụng nhưng nhận xét đã được thêm khi sự cố đã được đóng. – Holger

+1

@Holger DOH! Nghĩ rằng 'u119' khi tôi thấy' b119'. – Andreas

Các vấn đề liên quan