UnsupportedOperationException trong các giao diện khung của bộ sưu tập java


12

Nhìn qua Khung công tác bộ sưu tập Java, tôi nhận thấy khá nhiều giao diện có nhận xét (optional operation). Các phương thức này cho phép thực hiện các lớp thông qua UnsupportedOperationExceptionnếu chúng không muốn thực hiện phương thức đó.

Một ví dụ về điều này là addAllphương thức trong Set Interface.

Bây giờ, như đã nêu trong loạt câu hỏi này, các giao diện là một hợp đồng xác định cho những gì sử dụng có thể mong đợi.

Các giao diện rất quan trọng vì chúng tách biệt những gì một lớp làm với cách nó thực hiện. Hợp đồng xác định những gì khách hàng có thể mong đợi để nhà phát triển tự do thực hiện nó theo bất kỳ cách nào họ chọn, miễn là họ duy trì hợp đồng.

Giao diện là một mô tả về các hành động mà một đối tượng có thể làm ... ví dụ: khi bạn bật công tắc đèn, đèn sẽ sáng, bạn không quan tâm làm thế nào, chỉ là nó làm như vậy. Trong Lập trình hướng đối tượng, Giao diện là một mô tả về tất cả các chức năng mà một đối tượng phải có để là "X".

Tôi nghĩ rằng cách tiếp cận dựa trên giao diện là đẹp hơn đáng kể. Sau đó, bạn có thể chế giễu sự phụ thuộc của mình một cách độc đáo, và mọi thứ về cơ bản được kết hợp chặt chẽ hơn.

Điểm của một giao diện là gì?

Giao diện là gì?

Giao diện + Tiện ích mở rộng (mixin) so với Lớp cơ sở

Cho rằng mục đích của các giao diện là xác định hợp đồng và làm cho các phụ thuộc của bạn được ghép lỏng lẻo, không có một số phương pháp đưa ra một UnsupportedOperationExceptionmục đích đánh bại mục đích? Nó có nghĩa là tôi không còn có thể được thông qua Setvà chỉ sử dụng addAll. Thay vào đó, tôi phải biết việc triển khai Settôi đã được thông qua, vì vậy tôi có thể biết liệu tôi có thể sử dụng addAllhay không. Điều đó dường như khá vô giá trị với tôi.

Vậy quan điểm của nó là UnsupportedOperationExceptiongì? Có phải nó chỉ bù cho mã kế thừa, và họ cần dọn sạch giao diện của họ? Hay nó có một mục đích hợp lý hơn mà tôi đang thiếu?


Tôi không biết đó là JRE bạn đang sử dụng, nhưng tôi Oracle phiên bản 8 không định nghĩa addAlltrong HashSet. Nó trì hoãn việc thực hiện mặc định trong AbstractCollectionđó chắc chắn không ném UnsupportedOperationException.

@Snowman Bạn nói đúng. Tôi nhớ các tài liệu. Tôi sẽ chỉnh sửa câu hỏi của tôi.
MirroredFate

1
Tôi thích khởi động Eclipse và xem mã nguồn, nảy xung quanh các tham chiếu và định nghĩa mã để đảm bảo rằng tôi có nó đúng. Miễn là JRE được liên kết với src.zipnó hoạt động tuyệt vời. Nó giúp biết chính xác mã JRE đang chạy đôi khi và không trì hoãn JavaDoc, có thể hơi dài dòng.

Câu trả lời:


12

Nhìn vào các giao diện sau:

Các giao diện này đều khai báo các phương thức đột biến là tùy chọn. Điều này hoàn toàn ghi lại sự thật rằng lớp Bộ sưu tập có thể trả về các triển khai của các giao diện đó là bất biến: nghĩa là, các hoạt động đột biến tùy chọn đó được đảm bảo không thành công. Tuy nhiên, theo hợp đồng trong JavaDoc, tất cả các cài đặt của các giao diện đó phải cho phép các hoạt động đọc. Điều này bao gồm các triển khai "bình thường" như HashSetLinkedListcũng như các hàm bao không thay đổi trong Collections.

Tương phản với các giao diện hàng đợi:

Các giao diện này không chỉ định bất kỳ hoạt động tùy chọn nào: một hàng đợi, theo định nghĩa, được thiết kế để cung cấp và thăm dò các yếu tố theo cách thức của FIFO. Một hàng đợi bất biến là hữu ích như một chiếc xe không có bánh xe.


Một ý tưởng phổ biến xuất hiện nhiều lần là có một hệ thống phân cấp thừa kế có cả các đối tượng có thể thay đổi và bất biến. Tuy nhiên, tất cả đều có nhược điểm. Sự phức tạp làm vẩn đục vùng biển mà không thực sự giải quyết vấn đề.

  • Một giả thuyết Setcó thể có các hoạt động đọc và một giao diện con MutableSetcó thể có các hoạt động ghi. Liskov nói với chúng tôi rằng MutableSetsau đó có thể được truyền vào bất cứ thứ gì cần a Set. Lúc đầu, điều này nghe có vẻ ổn, nhưng hãy xem xét một phương pháp dự kiến ​​bộ cơ sở sẽ không được sửa đổi trong khi đọc: có thể hai luồng sử dụng cùng một bộ và vi phạm bất biến của tập không thay đổi. Điều này có thể gây ra sự cố, ví dụ nếu một phương thức đọc một phần tử từ tập hợp hai lần và nó ở đó lần đầu tiên nhưng không phải lần thứ hai.

  • Setcó thể không có triển khai trực tiếp, thay vào đó có MutableSetImmutableSetnhư các giao diện con được sử dụng để triển khai các lớp. Điều này có cùng một vấn đề như trên: tại một số điểm trong hệ thống phân cấp, một giao diện có các bất biến mâu thuẫn. Một người nói "bộ này phải có thể thay đổi" và bộ kia nói "bộ này không thể thay đổi."

  • Có thể có hai hệ thống phân cấp hoàn toàn riêng biệt cho các cấu trúc dữ liệu có thể thay đổi và bất biến. Điều này thêm một tấn phức tạp thêm cho những gì kết thúc là rất ít đạt được. Điều này cũng có điểm yếu cụ thể của các phương thức không quan tâm đến tính đột biến (ví dụ: tôi chỉ muốn lặp lại một danh sách) hiện phải hỗ trợ hai giao diện riêng biệt. Do Java được gõ tĩnh, điều này có nghĩa là các phương thức bổ sung để xử lý cả phân cấp giao diện.

  • Chúng ta có thể có một giao diện duy nhất và cho phép các triển khai đưa ra các ngoại lệ nếu một phương thức không áp dụng được với nó. Đây là con đường mà Java đã đi và nó có ý nghĩa nhất. Số lượng giao diện được giữ ở mức tối thiểu và không có bất biến bất biến vì giao diện tài liệu không đảm bảo về khả năng biến đổi theo bất kỳ cách nào . Nếu cần một bất biến bất biến, hãy sử dụng các hàm bao trong Collections. Nếu một phương thức không cần thay đổi một bộ sưu tập, chỉ cần không thay đổi nó. Hạn chế là một phương thức không thể đảm bảo một bộ sưu tập sẽ không thay đổi trong một luồng khác nếu nó được cung cấp một bộ sưu tập từ bên ngoài, nhưng đó là mối quan tâm của phương thức gọi (hoặc phương thức gọi của nó).


Đọc liên quan: Tại sao Java 8 không bao gồm các bộ sưu tập bất biến?


1
Nhưng nếu các phương thức là tùy chọn, chúng có vị trí nào trong giao diện? Chẳng hạn, không nên có một giao diện riêng có chứa các phương thức tùy chọn MutableCollection?
MirroredFate

Không. Không có cách nào để có các đối tượng có thể thay đổi và bất biến trong cùng một hệ thống phân cấp theo bất kỳ cách có ý nghĩa nào. Có một câu hỏi gần đây có một sơ đồ tốt cho thấy sự phức tạp và một lời giải thích tại sao đó là một ý tưởng tồi, nhưng nó đã bị xóa. Có lẽ ai đó biết một câu hỏi để giúp giải thích điều này, tôi không thể tìm thấy bất cứ điều gì. Nhưng tôi sẽ cập nhật câu trả lời của tôi để giải thích một chút.

Đó là một tuyên bố rộng rãi về hàng đợi bất biến. Tôi đã sử dụng một chỉ một vài ngày trước để giải quyết vấn đề này .
Karl Bielefeldt

@Snowman Nhưng điều đó dường như làm cho ra rằng các đối tượng có thể thay đổi và bất biến là đối lập của nhau. Tôi nghĩ rằng đối tượng bất biến thực sự chỉ là những đối tượng thiếu khả năng đột biến. Thành thật mà nói, cách thức hiện tại phức tạp và lộn xộn hơn, bởi vì bạn phải tìm ra đâu là một triển khai có thể thay đổi và điều gì không. Đối với tôi, dường như sự khác biệt duy nhất giữa việc đặt tất cả các phương thức trong một giao diện trái ngược với việc tách ra các phương thức có thể thay đổi là một điều rõ ràng.
MirroredFate

@MirroredFate đọc bản chỉnh sửa gần đây nhất của tôi.

2

Về cơ bản là YAGNI. Tất cả các bộ sưu tập cụ thể trong thư viện tiêu chuẩn đều có thể thay đổi, thực hiện hoặc kế thừa các hoạt động tùy chọn. Họ không quan tâm đến các bộ sưu tập bất biến mục đích chung và cũng không làm đại đa số các nhà phát triển Java. Họ sẽ không tạo ra toàn bộ hệ thống phân cấp giao diện chỉ dành cho các bộ sưu tập bất biến, sau đó không bao gồm bất kỳ triển khai nào.

Mặt khác, có một vài giá trị mục đích đặc biệt hoặc các bộ sưu tập "ảo" có thể rất hữu ích như bất biến, chẳng hạn như tập rỗngnCopies . Ngoài ra, có các bộ sưu tập bất biến của bên thứ ba (chẳng hạn như Scala), có thể muốn gọi mã Java hiện có, vì vậy chúng để lại khả năng cho các bộ sưu tập bất biến mở theo cách ít gây gián đoạn nhất.


Ok, điều đó có ý nghĩa. Dường như vẫn tiếp cận vấn đề từ hướng sai. Tại sao không bắt đầu bằng cách xác định các giao diện bộ sưu tập bất biến, và sau đó xác định các giao diện có thể thay đổi cho việc triển khai bộ sưu tập có thể thay đổi?
MirroredFate
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.