Comparator.reversed () không biên dịch bằng lambda


111

Tôi có một danh sách với một số đối tượng Người dùng và tôi đang cố gắng sắp xếp danh sách, nhưng chỉ hoạt động bằng cách sử dụng tham chiếu phương thức, với biểu thức lambda trình biên dịch đưa ra lỗi:

List<User> userList = Arrays.asList(u1, u2, u3);
userList.sort(Comparator.comparing(u -> u.getName())); // works
userList.sort(Comparator.comparing(User::getName).reversed()); // works
userList.sort(Comparator.comparing(u -> u.getName()).reversed()); // Compiler error

Lỗi:

com\java8\collectionapi\CollectionTest.java:35: error: cannot find symbol
            userList.sort(Comparator.comparing(u -> u.getName()).reversed());
                                                     ^
symbol:   method getName()
location: variable u of type Object
1 error

Câu trả lời:


145

Đây là một điểm yếu trong cơ chế truyền thông kiểu của trình biên dịch. Để suy ra loại utrong lambda, loại đích cho lambda cần phải được thiết lập. Điều này được thực hiện như sau. userList.sort()đang mong đợi một đối số thuộc loại Comparator<User>. Trong dòng đầu tiên, Comparator.comparing()cần phải trả lại Comparator<User>. Điều này ngụ ý rằng Comparator.comparing()cần Functionphải có một Userđối số. Vì vậy, trong lambda ở dòng đầu tiên, uphải là loại Uservà mọi thứ hoạt động.

Trong dòng thứ hai và thứ ba, việc nhập mục tiêu bị gián đoạn bởi sự hiện diện của lệnh gọi tới reversed(). Tôi không hoàn toàn chắc chắn tại sao; cả kiểu nhận và kiểu trả về reversed()đều Comparator<T>như vậy nên có vẻ như kiểu đích nên được truyền ngược lại cho người nhận, nhưng không phải vậy. (Như tôi đã nói, đó là một điểm yếu.)

Trong dòng thứ hai, tham chiếu phương thức cung cấp thông tin loại bổ sung lấp đầy khoảng trống này. Thông tin này không có trong dòng thứ ba, do đó, trình biên dịch suy luận uObject(dự phòng suy luận của phương án cuối cùng), không thành công.

Rõ ràng nếu bạn có thể sử dụng tham chiếu phương thức, hãy làm điều đó và nó sẽ hoạt động. Đôi khi bạn không thể sử dụng tham chiếu phương thức, ví dụ: nếu bạn muốn truyền một tham số bổ sung, vì vậy bạn phải sử dụng biểu thức lambda. Trong trường hợp đó, bạn sẽ cung cấp một loại tham số rõ ràng trong lambda:

userList.sort(Comparator.comparing((User u) -> u.getName()).reversed());

Có thể trình biên dịch được cải tiến để giải quyết trường hợp này trong một bản phát hành trong tương lai.


28
Lambdas được chia thành kiểu ngầm định (không có kiểu kê khai cho các tham số) và kiểu rõ ràng ; tham chiếu phương pháp được chia thành chính xác (không quá tải) và không chính xác . Khi một cuộc gọi phương thức chung ở vị trí bộ nhận có các đối số lambda và các tham số kiểu không thể được suy ra đầy đủ từ các đối số khác, bạn cần cung cấp một lambda rõ ràng, một tham chiếu phương thức chính xác, một kiểu đích hoặc các nhân chứng kiểu rõ ràng cho lệnh gọi phương thức chung để cung cấp thông tin loại bổ sung cần thiết để tiếp tục.
Brian Goetz

1
@StuartMarks, bạn "không hoàn toàn chắc chắn tại sao" trình biên dịch lại hoạt động như vậy. Nhưng đặc tả ngôn ngữ nói gì? Nên có đủ thông tin để xác định các kiểu chung, theo đặc điểm ngôn ngữ? Nếu vậy, đây là một lỗi trình biên dịch và cần được gửi và xử lý tương ứng. Nếu không, nó là một lĩnh vực mà ngôn ngữ Java cần được cải thiện. Đó là cái nào?
Garret Wilson

8
Tôi nghĩ rằng chúng ta có thể coi các nhận xét của Brian là dứt khoát, vì anh ấy đã viết thông số kỹ thuật được đề cập :-)
minimalis

1
Đáng buồn là không có điều này giải thích tại sao nó hoạt động mà không bị đảo ngược trong khi nó không hoạt động với đảo ngược.
Chris311

90

Bạn có thể khắc phục hạn chế này bằng cách sử dụng hai đối số Comparator.comparingvới Comparator.reverseOrder()làm đối số thứ hai:

users.sort(comparing(User::getName, reverseOrder()));

4
Đẹp. Tôi thích điều này hơn là sử dụng lambda được nhập rõ ràng. Hoặc, tốt hơn users.sort(reverseOrder(comparing(User::getName)));,.
rolve

10
Lưu ý rằng reverseOrder(Comparator<T>)phương thức trên là trong java.util.Collections, không phải trong Comparator.
rolve
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.