簡體   English   中英

為什么 Collections.sort 可以不帶比較器,但 List.sort 必須帶比較器?

[英]Why can Collections.sort take no comparator but List.sort must take a comparator?

我不明白為什么 List.sort() 沒有沒有比較器的版本的邏輯。

特別是我看到可以用 null 調用 List.sort:
list.sort(null) ,它似乎使用自然順序進行排序。

我注意到我的 IDE Collections.sort() 調用 List.sort(null),所以我想知道為什么 List.sort 似乎是最近在 ZD52387880E1EA22817A7,2D37592131 中引入的一個簡單版本,其中很多沒有比較器不需要案例。

另外我不確定在這種情況下是否最好調用 List.sort(null) 以避免額外的調用,或者是否仍然更喜歡調用 Collections.sort() 並避免丑陋的 null 參數。

tldr

這是一個設計決定,混合了一些歷史原因。 可以添加list.sort()但它不能確保編譯時的安全,只有運行時。 對於 JDK 來說,這將是一個相當奇怪和不尋常的設計。


集合#sort

Collections,因為它可以在方法聲明中指定類型邊界,所以有可能強制Comparable元素:

public static <T extends Comparable<? super T>> void sort(List<T> list)

因此該方法可以確保集合包含Comparable元素。 所以不需要Comparator器。


列表#排序

List無法做到這一點。 它的泛型類型必須允許一切,您必須能夠使用List<Dog>盡管那些可能不是Comparable

因此,如果存在list.sort() ,那么此方法將需要確定列表泛型類型T是否為Comparable 但是這些信息只存在於運行時,我們希望它在編譯時得到一個好的設計。

因為這會導致糟糕的設計, list.sort()不存在。 因此,強制使用Comparator的額外方法可以確保編譯時的安全性。


list.sort(null)

list.sort(null)而不是list.sort()顯然是一種設計選擇,在我看來是一個很好的選擇。 如前所述, List無法在編譯時確保安全。 因此,為了運行時安全性,唯一的選擇是 go,這不是那么好。

有一個list.sort()只在某些時候有效並拋出異常,否則將是一個奇怪的設計選擇。 然而,像list.sort(null)這樣的調用對任何用戶來說都更加清晰。 特別是,更清楚的是,這將被運行時決策覆蓋,而不是編譯時檢查。

您可能希望使其顯式化並為其提供使用自然排序的普通Comparator

list.sort(Comparator.naturalOrder());

這至少對讀者來說會更清楚。


歷史

您現在可能想知道為什么List.sort(null)甚至是受支持的功能,以及為什么它們不要求您始終為它提供顯式Comparator 我無法調查開發人員的想法,但我懷疑是歷史原因。 JDK 中有很多類似的示例,尤其是排序方面。

這主要是因為 Java 保持了向后兼容性。 Generics 是在 Java 5 中引入的,因此之前存在的處理容器的所有內容在設計時都沒有考慮到類型安全。

有幾個高度相關的例子:

  • Arrays#sort(Object[]) (自 Java 1.2 起)不強制Comparable 因此,他們必須在 Java 5 Arrays.sort(T[], Comparator)中添加額外的重載,就像List示例一樣。
  • 方法Collections.sort(T[], Comparator)實際上接受null作為比較器。 一個糟糕的設計選擇,但它是在 generics 還不存在時做出的。 所以他們不能再刪除這個功能了。
  • 有趣的是,他們決定讓新方法List.sort(Comparator)也支持null 然而,在Stream.sort(Comparator)他們沒有。 這是 JDK 中一個奇怪的不一致。

當您不提供比較器時,將使用natural排序,這僅適用於實現Comparable的類型。

如果您查看Collections.sort()的方法定義:

    public static <T extends Comparable<? super T>> void sort(List<T> list)

元素類型的范圍是這樣的,它必須實現Comparable

List沒有這種約束,因為在很多情況下,您希望列表保存沒有自然順序的事物。 因此,您不能調用sort() ,因為List不能保證它包含具有自然順序的元素。

您可以對此進行測試:

以下是編譯錯誤:

    List<Object> objs = new ArrayList<>();
    objs.add(new Object());
    objs.add(new Object());

    Collections.sort(objs);

因為Object沒有實現Comparable<Object> ,所以除非您提供比較器,否則沒有明智的方法對它們進行排序。

如果我繞過Collections class 並這樣做:

    List<Object> objs = new ArrayList<>();
    objs.add(new Object());
    objs.add(new Object());

    objs.sort(null);

我得到一個例外,解釋相同:

    java.lang.ClassCastException: class java.lang.Object cannot be cast to class java.lang.Comparable

我不明白為什么 list.sort() 沒有沒有比較器的版本的邏輯?

這也是我不明白的地方,但我想這只是介紹該方法的程序員的個人喜好。

由於 Java 1.8 支持接口中的默認方法,因此很容易添加不帶參數List.sort()的重載版本以明確該參數是可選的。 該方法可以簡單地委托給sort(Comparator)方法。

我通常會引入重載方法來明確哪些參數是可選的,哪些不是。

我的簡單規則是:

  • 方法指定一個參數,因為它需要它。 因此,默認情況下它是強制性的。
  • 如果它是可選的,則提供不帶該參數的重載方法。

另外我不確定在這種情況下最好調用 list.sort(null) 以避免額外的調用,或者仍然首選 collection.sort() 並避免丑陋的 null 參數。

我不會擔心這一點,因為如果那一個額外的電話是您的問題,那么您就真的有麻煩了。 所以選擇一個你認為更容易理解的版本。 JIT 編譯器也有可能通過內聯刪除調用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM