Tại sao Java không làm suy luận kiểu?


44

Tôi đã luôn tự hỏi tại sao Java không thực hiện suy luận kiểu cho rằng ngôn ngữ là chính nó và VM của nó rất trưởng thành. Google Go là một ví dụ về ngôn ngữ có loại suy luận xuất sắc và nó làm giảm số lượng gõ mà người ta phải làm. Có bất kỳ lý do đặc biệt nào đằng sau tính năng này không phải là một phần của Java không?


3
quy tắc tương thích ngược trong một ngôn ngữ cũ và phổ biến như java
ratchet freak

9
@ratchetfreak Có thể thêm suy luận không được thêm vào theo cách tương thích ngược? Các chương trình cũ hơn sẽ chỉ cung cấp nhiều thông tin loại hơn mức cần thiết.

1
Nó có thể có một số tác dụng ngoài ý muốn khi được sử dụng với Type Erasure. docs.oracle.com/javase/tutorial/java/generics/ từ
Zachary Yates

4
Lưu ý rằng Java 8 sẽ mang lại nhiều suy luận kiểu với tính năng Lambda của nó: bạn có thể viết lambdas phức tạp mà không đề cập đến bất kỳ loại nào và mọi thứ được suy luận.
Joachim Sauer

4
Suy luận kiểu biến cục bộ đang đến với Java: JEP 286: Suy luận kiểu biến cục bộ
Trang Jimmy

Câu trả lời:


60

Về mặt kỹ thuật, Java có kiểu suy luận khi sử dụng generic. Với một phương pháp chung chung như

public <T> T foo(T t) {
  return t;
}

Trình biên dịch sẽ phân tích và hiểu rằng khi bạn viết

// String
foo("bar");
// Integer
foo(new Integer(42));

Một chuỗi sẽ được trả về cho cuộc gọi đầu tiên và một số nguyên cho cuộc gọi thứ hai dựa trên những gì được đưa vào làm đối số. Bạn sẽ nhận được kết quả kiểm tra thời gian biên dịch thích hợp. Ngoài ra, trong Java 7, người ta có thể nhận được một số loại suy luận bổ sung khi khởi tạo các tổng quát như vậy

Map<String, String> foo = new HashMap<>();

Java đủ tử tế để điền vào dấu ngoặc góc trống cho chúng tôi. Bây giờ tại sao Java không hỗ trợ kiểu suy luận như là một phần của phép gán biến? Tại một thời điểm, đã có một RFE cho kiểu suy luận trong các khai báo biến, nhưng điều này đã bị đóng là "Sẽ không sửa" bởi vì

Con người được hưởng lợi từ sự dư thừa của khai báo loại theo hai cách. Đầu tiên, loại dự phòng đóng vai trò là tài liệu có giá trị - người đọc không phải tìm kiếm khai báo getMap () để tìm ra loại nào trả về. Thứ hai, sự dư thừa cho phép lập trình viên khai báo loại dự định và do đó được hưởng lợi từ việc kiểm tra chéo được thực hiện bởi trình biên dịch.

Người đóng góp đã đóng cái này cũng lưu ý rằng nó chỉ cảm thấy "không giống java", mà tôi là người đồng ý. Sự dài dòng của Java có thể là cả một phước lành và một lời nguyền, nhưng nó làm cho ngôn ngữ trở thành như vậy.

Tất nhiên, RFE cụ thể đó không phải là kết thúc của cuộc trò chuyện đó. Trong Java 7, tính năng này một lần nữa được xem xét , với một số triển khai thử nghiệm được tạo ra, bao gồm một do chính James Gosling thực hiện. Một lần nữa, tính năng này cuối cùng đã bị bắn hạ.

Với việc phát hành Java 8, giờ đây chúng ta có được kiểu suy luận như là một phần của lambdas như sau:

List<String> names = Arrays.asList("Tom", "Dick", "Harry");
Collections.sort(names, (first, second) -> first.compareTo(second));

Trình biên dịch Java có thể xem xét phương thức Collections#sort(List<T>, Comparator<? super T>)và sau đó là giao diện Comparator#compare(T o1, T o2)và xác định điều đó firstsecondnên là một Stringchương trình cho phép người lập trình từ bỏ việc phải khôi phục kiểu trong biểu thức lambda.


5
First, the redundant type serves as valuable documentation - readers do not have to search for the declaration of getMap() to find out what type it returns- vâng, nếu đó là HashMap<String, Integer> map = foo.getMap()tôi đồng ý - trong C # tôi thường không sử dụng vartrong những trường hợp như vậy, mặc dù tôi có thể. Nhưng tranh luận này không giữ nước nếu nó HashMap<String, Integer> map = new HashMap<String, Integer>(). Đây là sự dư thừa thực sự và tôi thấy không có lợi ích gì khi phải viết tên loại hai lần. Và làm thế nào tôi có lợi ở đây từ kiểm tra chéo trình biên dịch, tôi không hiểu gì cả.
Konrad Morawski

9
Vâng và điều đó tốt cho thuốc generic, nhưng tôi vẫn bỏ lỡ tương đương với C # vartrong Java.
Konrad Morawski

15
Đối với nó là "giống như java", câu chuyện (cheesy) này xuất hiện trong tâm trí;) 9gag.com/gag/2308699/-this-is-how-things-are-done-around-here
Konrad Morawski

6
Hơn nữa, kiểu trả về của hàm thường rõ ràng hoặc không cần thiết và thậm chí trong trường hợp IDE không có thể gắn cờ loại đó trong nửa giây.
Phoshi

8
Tôi tin rằng trích dẫn chính thức Humans benefit from the redundancylà câu trả lời thực sự cho câu hỏi hiện tại, bởi vì mọi lời biện minh tôi đã đọc dường như là một lý do vô cớ, vô căn cứ và lố bịch từ các nhà thiết kế Java: Cả C # và C ++ đều có tính năng, các nhà thiết kế C # và C ++ không kém thẩm quyền hơn Java và mọi người đều hài lòng khi sử dụng nó. Điều gì sẽ khiến các nhà phát triển Java khác với các nhà phát triển C # hoặc C ++? Đây là lý do tại sao tôi đồng ý với @KonradMorawski, "Đây là cách mọi thứ được thực hiện ở đây" dường như một lần nữa là lý do hậu trường thực sự cho điều đó.
paercebal

16

Chà, trước hết, kiểu suy luận không liên quan gì đến sự trưởng thành của thời gian chạy, cho dù thời gian chạy đó là CPU 30 năm hay VM quá mới nên các bit vẫn sáng bóng. tất cả là về trình biên dịch.

Điều đó nói rằng, nó được phép cho thuốc generic, lý do tại sao nó không được phép cho các loại không chung chung dường như là vì triết lý - không có gì ngăn cản các nhà thiết kế thêm nó.

Cập nhật: trông giống như java 10 hỗ trợ nó - http://openjdk.java.net/jeps/286


5

Theo như tôi biết, khi Java được thiết kế vào đầu những năm 1990, suy luận kiểu này không phổ biến trong các ngôn ngữ chính thống (nhưng nó đã là một khái niệm rất nổi tiếng, ví dụ như trong ML). Vì vậy, tôi có thể tưởng tượng rằng suy luận kiểu đó có lẽ không được hỗ trợ vì Java nhắm vào các lập trình viên đến từ C ++, Pascal hoặc các ngôn ngữ chính khác không có nó (nguyên tắc ít gây ngạc nhiên nhất).

Ngoài ra, một trong những nguyên tắc thiết kế của Java là viết mọi thứ rõ ràng để đảm bảo rằng người lập trình và trình biên dịch có cùng sự hiểu biết về mã: sao chép thông tin giúp giảm nguy cơ lỗi. Tất nhiên, nó có thể là một vấn đề của hương vị cho dù gõ thêm một vài ký tự có xứng đáng với sự an toàn bổ sung mà nó cung cấp hay không, nhưng đây là triết lý thiết kế theo Java: viết mọi thứ rõ ràng.

Tôi không biết liệu Java sẽ có loại suy luận trong tương lai hay không nhưng IMO sẽ là một cuộc cách mạng lớn cho ngôn ngữ (như Glenn Nelson đã đề cập, nó được mô tả là "không giống java") và sau đó người ta cũng có thể xem xét bỏ tên Java ủng hộ một tên mới.

Nếu bạn muốn sử dụng ngôn ngữ JVM với kiểu suy luận, bạn có thể sử dụng Scala.


2

Tôi có thể nghĩ về một vài lý do có thể. Một là gõ rõ ràng là tự viết tài liệu. Java thường làm cho điều này là một ưu tiên hơn so với việc xử lý. Một lý do khác có thể là trong trường hợp loại này hơi mơ hồ. Giống như khi một kiểu hoặc bất kỳ kiểu con có thể đáp ứng một thói quen. Giả sử bạn muốn sử dụng Danh sách, nhưng ai đó xuất hiện và sử dụng phương thức dành riêng cho ArrayList. JIT sẽ suy ra một ArrayList và tiếp tục ngay cả khi bạn muốn có một lỗi biên dịch.


8
GridBagLayout Gridbag = new GridBagLayout (); Thêm vào tài liệu tự? Sự lặp lại thuần túy của nó.
Anders Lindén

3
Nó phân biệt từ một trường hợp mà hai loại không giống nhau. Bạn có thể dễ dàng gán một thể hiện của một lớp con.
nhộn

Let's say you want to use a List, but someone comes along and uses a method exclusive to ArrayList. The JIT would infer an ArrayList and carry on even if you wanted a compilation error- Tôi không hiểu chút này. Kiểu suy luận diễn ra tại thời điểm kích thích một biến, không gọi một phương thức trên nó. Có lẽ bạn có thể cho thấy một ví dụ về những gì bạn có ý nghĩa?
Konrad Morawski

2
@KonradMorawski: Tôi giả sử rằng anh ta có nghĩa là nếu một phương thức trả về ArrayList, kiểu sẽ được suy ra. Nếu bạn muốn coi một loại là một cái gì đó khác với loại trả về, bạn không thể sử dụng suy luận. Mặc dù vậy, tôi không hiểu làm thế nào điều này có thể là một vấn đề trong một cơ sở mã ở bất cứ nơi nào gần lành mạnh.
Phoshi

JIT sẽ không đóng vai trò gì trong suy luận kiểu. kiểu suy luận là một hiện tượng thời gian biên dịch. và nếu một biến được khai báo là tham chiếu đến Danh sách, cố gắng truy cập các thành viên ArrayList trên đó sẽ không gõ kiểm tra và bạn gặp lỗi biên dịch
sara

0

Nó mâu thuẫn với khuyến nghị được thiết lập tốt để khai báo các biến bằng giao diện chung nhất sẽ phù hợp với nhu cầu của bạn và khởi tạo chúng với một lớp triển khai thích hợp, như trong

Collection<String> names = new ArrayList<>();

Hiệu quả

var names = new ArrayList<String>();

không có gì ngoài cú pháp đường cho

ArrayList<String> names = new ArrayList<String>();

Nếu bạn muốn điều đó, IDE của bạn có thể tạo nó từ new ArrayList<String>()biểu thức với "một lần nhấp" (refactor / tạo biến cục bộ), nhưng hãy nhớ rằng nó mâu thuẫn với khuyến nghị "sử dụng giao diện".

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.