Nhập suy luận trong Java 8


30

Việc giới thiệu ký hiệu lambda mới (xem ví dụ bài viết này ) trong Java 8 sẽ yêu cầu một số loại suy luận?

Nếu vậy, hệ thống kiểu mới sẽ tác động đến toàn bộ ngôn ngữ Java như thế nào?

Câu trả lời:


47

Có một chút thông tin không chính xác trong câu trả lời của ratchet freak và trong luồng nhận xét của nó. Tôi sẽ trả lời ở đây trong một câu trả lời, vì một nhận xét quá nhỏ. Ngoài ra, vì đây là câu trả lời cho tất cả, tôi cũng sẽ cố gắng trả lời câu hỏi ban đầu. (Lưu ý tuy nhiên tôi không phải là chuyên gia về các hệ thống loại.)

Đầu tiên, các câu trả lời ngắn cho câu hỏi ban đầu là Có và Không. Có, Java 8 sẽ có suy luận kiểu nhiều hơn đáng kể so với Java 7 và Không, không có hệ thống loại "mới" trong Java 8, mặc dù có một số thay đổi nhỏ .

Java 8 sẽ vẫn được gõ tĩnh và nó vẫn sẽ có sự phân đôi giữa các lớp và giao diện. Không có loại mới như loại chức năng. Loại lambda về cơ bản là một "giao diện chức năng" là một giao diện thông thường với một phương thức trừu tượng duy nhất.

Các giao diện bây giờ có thể có mã dưới dạng các phương thức mặc định, nhưng mô hình kế thừa đơn của các lớp và nhiều kế thừa của các giao diện vẫn giống nhau. Tất nhiên, có một số điều chỉnh, chẳng hạn như các quy tắc để giải quyết phương thức với sự có mặt của các phương thức mặc định, nhưng các nguyên tắc cơ bản là không thay đổi.

Bất kỳ loại nào được suy luận theo loại suy luận có thể được viết ra một cách rõ ràng. Để sử dụng ví dụ của ratchet freak ,

Collections.<MyClass>sort(list, (a, b) -> { return a.order - b.order; });

về cơ bản là đường cho

Collections.<MyClass>sort(list,
    (Comparator<MyClass>)((MyClass a, MyClass b) -> { return a.order - b.order; }));

Vì vậy, tuyên bố "kiểu suy luận kiểu lấp lánh không yêu cầu bất kỳ sự mở rộng nào của hệ thống kiểu" về cơ bản là chính xác.

Nhưng để trở về đường cú pháp, tôi sẽ lặp lại tuyên bố của mình rằng biểu thức lambda không phải là đường cú pháp cho một lớp bên trong ẩn danh. Ratchet freak tuyên bố rằng một biểu thức lambda được dịch thành một khởi tạo lớp bên trong ẩn danh và Sparkleshy chỉ đơn giản xác nhận lại rằng lambda đường cú pháp cho một lớp bên trong ẩn danh, nhưng những tuyên bố này không chính xác. Họ có thể dựa trên thông tin lỗi thời. Việc triển khai lambda sớm đã thực hiện lambdas theo cách này, nhưng mọi thứ đã thay đổi.

Các biểu thức Lambda khác biệt về mặt ngữ nghĩa với các lớp bên trong và chúng được triển khai khác với các lớp bên trong.

Các biểu thức Lambda khác biệt về mặt ngữ nghĩa với các lớp bên trong theo một vài cách. Đánh giá một biểu thức lambda không cần phải tạo một thể hiện mới mỗi lần. Họ cũng có ngữ nghĩa chụp khác nhau, ví dụ, họ nắm bắt điều này khác nhau. Trong một lớp bên trong, đây là thể hiện của lớp bên trong, trong khi trong lambda, đây là thể hiện kèm theo. Hãy xem xét những điều sau đây:

public class CaptureThis {
    void a(Runnable r) { r.run(); }

    void b() {
        a(new Runnable() { public void run() { System.out.println(this); }});
        a(() -> System.out.println(this));
    }

    public String toString() { return "outer"; }

    public static void main(String[] args) { new CaptureThis().b(); }
}

Trong bản dựng lambda JDK 8 gần đây (tôi đã sử dụng b69 ), đầu ra sẽ giống như sau:

CaptureThis$1@113de03
outer

Hơn nữa, các biểu thức lambda được thực hiện hoàn toàn khác với các lớp bên trong. Nếu bạn so sánh đầu ra được phân tách, bạn sẽ thấy rằng mã lớp bên trong dễ dàng biên dịch với việc tạo và gọi tới một hàm tạo của Capture This $ 1, trong khi biểu thức lambda biên dịch thành một lệnh được kích hoạt có nghĩa là Runnable thông qua nghĩa là không xác định. Để được giải thích đầy đủ về cách thức hoạt động của nó và tại sao, hãy xem bài nói về JavaOne 2012 của Brian Goetz : Lambda: A Peek Under The Hood .


2
". họ nắm bắt này cách khác nhau Trong một lớp bên trong, đây là ví dụ lớp bên trong, trong khi ở một lambda, đây là ví dụ kèm theo cân nhắc những điều sau đây:" vẫn có thể được thực hiện với cú pháp đường bằng cách thay thế tất cả thisvớiMyClass.this
ratchet quái

4
Tất cả mọi thứ vượt ra ngoài trình biên dịch chương trình (và đôi khi thậm chí là như vậy) được cho là đường cú pháp. Nhưng lambdas không phải là cú pháp đường cho các lớp bên trong (bất kỳ nữa). Chúng phục vụ một mục tiêu tương tự và có một số điểm tương đồng, nhưng dưới mui xe chúng (có thể quan sát được) khác nhau.
Joachim Sauer

1
"Các biểu thức Lambda khác biệt về mặt ngữ nghĩa với các lớp bên trong và chúng được triển khai khác với các lớp bên trong.": Cảm ơn vì lời giải thích rất tốt (+1). Điều vẫn chưa rõ ràng với tôi là tại sao lambdas không được triển khai dưới dạng đường cú pháp cho các lớp ẩn danh đặc biệt hay nói cách khác, lợi thế của sự phức tạp thêm được giới thiệu bởi ngữ nghĩa mới là gì? Vấn đề gì giải quyết mà không thể được giải quyết với các lớp bên trong ẩn danh? (Nhưng tôi vẫn phải xem liên kết bạn đã đăng, có thể tôi sẽ tìm thấy câu trả lời ở đó.)
Giorgio

1
@Joachim Sauer: Tôi sẽ coi đường cú pháp là một cú pháp mới cho một ngữ nghĩa hiện có. Khi ngữ nghĩa mới được giới thiệu, tôi nghĩ bạn không thể nói về đường cú pháp. Theo nghĩa này, tôi không nghĩ rằng bạn có thể lập luận rằng mọi thứ ngoài trình biên dịch là đường cú pháp.
Giorgio

3
@Giorgio: liên quan đến lý do tại sao lambda không chỉ là cú pháp đường cho các lớp bên trong ẩn danh, hóa ra đã có một cuộc thảo luận lớn về điều này. Thư này từ Brian Goetz tóm tắt quyết định: mail.openjdk.java.net/pipermail/lambda-dev/2011-August/ . TL; DR nó để cánh cửa mở cho sự phát triển trong tương lai và chúng ta có được hiệu suất tốt hơn ngày hôm nay. Goetz thực sự đang trả lời một câu hỏi liên quan, Là đối tượng lambdas? Nhưng nếu câu trả lời là Không hoặc thậm chí Có lẽ điều đó ngụ ý rằng chúng không thể là đường cho các lớp bên trong.
Stuart Marks
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.