2014-10-30 69 views
6

ImmutableSet實現了Set接口。對ImmutableSet無意義的功能現在稱爲Set的「可選操作」。我假設這樣的情況。因此ImmutableSet現在爲許多可選操作拋出了UnsupportedOperationException他們爲什麼決定讓接口具有「可選操作」

這似乎倒退給我。我被告知Interface是一個合約,以便您可以在不同的實現中使用強加功能。可選操作的方法似乎從根本上改變(矛盾?)接口意味着要做什麼。今天實現這個,我會將Set接口分成兩個接口:一個接口用於不可變操作,另一個接口擴展這些mutators操作。 (非常快,關閉袖口解決方案)

我知道技術的變化。我不是說應該這樣或那樣的。我的問題是,這種變化是否反映了Java的某些基礎哲學的變化?它只是更多的東西,使事情向後兼容?我對接口有不完全的理解嗎?

+1

*「接口是一個合約,因此您可以在不同的實現中使用強加功能」 - 這不就是集合接口最終成功完成的事情嗎?使用異常作爲功能的一部分可能不受歡迎,但它是一種語言功能,正確使用或實現集合時沒有任何可選的功能。你必須拋出/期待例外。儘管如此,我已經希望獲得更薄的接口或至少像'.supportsRemoval()'這樣的方法。 'ImmutableSet'擴展了'Set',它指定了現在保證拋出哪些方法。 – zapl 2014-10-30 19:46:56

回答

9

Java Collections API Design FAQ回答這個問題詳細:

問:你爲什麼不直接支持不可改變的核心集合接口,讓您可以與可選的操作(和UnsupportedOperationException異常)做了嗎?

答:這是整個API中最具爭議性的設計決策。顯然,靜態(編譯時)類型檢查是非常可取的,並且是Java中的常態。如果我們相信這是可行的,我們會支持它。不幸的是,試圖實現這個目標會導致接口層次的大小激增,並且不能成功地消除對運行時異常的需要(儘管它們大大減少了它)。

Doug Lea編寫了一個廣受歡迎的Java集合包,它的界面層次體現了可變性的區別,他不再相信這是一個可行的方法,基於用戶體驗他的集合包。用他的話來說(來自個人信件)「很多人說我很痛苦,強大的靜態類型不適用於Java中的集合接口。」

爲了說明血腥細節中的問題,假設您想要將可修改性的概念添加到層次結構中。您需要四個新的接口:ModifiableCollection,ModifiableSet,ModifiableList和ModifiableMap。以前簡單的層次結構現在是一個混亂的層次結構。此外,您還需要一個新的Iterator接口,以便與不可修改的集合一起使用,該接口不包含刪除操作。現在你可以拋棄UnsupportedOperationException了嗎?不幸的是,考慮數組。考慮數組。他們實施大部分列表操作,但不能刪除和添加。他們是「固定大小」列表。如果要在層次結構中捕獲這個概念,則必須添加兩個新接口:VariableSizeList和VariableSizeMap。您不必添加VariableSizeCollection和VariableSizeSet,因爲它們與ModifiableCollection和ModifiableSet相同,但爲了一致性,您可以選擇添加它們。此外,您還需要一種不支持添加和刪除操作的新ListIterator,以配合不可修改的List。現在我們有多達十個或十二個接口,再加上兩個新的Iterator接口,而不是我們原來的四個接口。我們完了嗎?考慮日誌(例如錯誤日誌,可恢復數據對象的審計日誌和日誌)。它們是自然附加序列,除了刪除和設置(替換)以外,它們都支持所有的列表操作。他們需要一個新的核心接口和一個新的迭代器。

那麼不可變的集合,而不是不可修改的集合呢? (即客戶不能更改的集合,並且由於任何其他原因決不會改變)。許多人認爲這是最重要的區別,因爲它允許多個線程同時訪問集合而不需要同步。將此支持添加到類型層次結構中需要四個接口。

現在我們可以使用二十個左右的接口和五個迭代器,而且幾乎可以肯定的是,在實踐中仍然存在一些集合,這些集合並不能完全適合任何接口。例如,Map返回的collection-views是自然的只刪除集合。另外,有些集合會根據它們的值拒絕某些元素,所以我們仍然沒有廢除運行時異常。

當所有的事情都說完之後,我們覺得通過提供一小組可以拋出運行時異常的核心接口來回避整個問題是一種合理的工程折衷。

總之,具有類似於Set可選操作界面做是爲了防止在需要不同接口的數量呈指數爆炸。它不像「不可變」和「可變」那麼簡單。然後,Guava的ImmutableSet必須實現Set以與所有其他使用Set的代碼進行互操作。這並不理想,但實際上沒有更好的辦法。

+0

讓集合擴展ImmutableCollection(或給它一個更好的名稱,ReadableCollection)會不會更直觀,以便更改集合的方法可以不在基本接口之外?事實證明,它打破了Liskov替代原則。 – 2014-10-30 15:58:28

+1

@ B.Dalton即使原則上可修改,由於類型,值或容量限制,或者Map返回的只刪除集合視圖,Collection仍將具有可選操作,如上所述。與此同時,ReadableCollection接口將是無用的:你不能依賴ReadableCollection是不可變的,因爲它可能是一個可變的子類,並且你不能將它傳遞給其他代碼,期望它們不能被它們修改,因爲這樣代碼可以將其轉換爲Collection。所以分離不會實現任何事情。 – Boann 2014-10-30 16:19:21

+0

雖然我不知道更好的解決方案,但它似乎是接口(有?)的一個目的,它們將問題拖入錯誤的解決方案。你知道更好的解決這個問題的其他範例嗎? – 2014-10-30 18:10:48

相關問題