簡體   English   中英

為什么 Java 中沒有“List.reverse()”方法?

[英]Why is there no “List.reverse()” method in Java?

在 Java 中,要反轉 List 中的元素,我需要使用:

Collections.reverse(list)

我只是想知道為什么 Java 不在List接口中實現 reverse 方法,以便我可以像這樣執行就地反向操作:

list.reverse()

有沒有人對此有任何想法?

為什么 Java 中沒有List.reverse()方法?

因為有一個Collections.reverse(List)方法。

因為 API 設計者認為強制每個List實現1實現一個在 99.9% 的時間都沒有使用的方法2是一個壞主意。 這可以通過使方法“可選”來解決,但這也有缺點; 例如運行時異常。

因為對於某些類型的列表(例如流包裝器/適配器),實現就地反向將是有問題的。 它通過要求將列表具體化來更改列表的內存使用特性。

另請注意, Collection提供的reverse()的通用實現( 源代碼)使用set來交換元素。 它接近於標准列表類型的最佳選擇。


@shmosel 評論:

我假設 OP 是在問為什么它沒有像 List.sort() 那樣作為默認方法添加。

好點。 可能 99.9% 的論點適用。 請記住,這只會幫助那些使用 Java 8 或更高版本編譯器等構建的代碼庫的人。


1 - 這包括您的代碼庫和第 3 方庫中的實現。

2 - 86% 的統計數據用於戲劇效果:-)

出於同樣的原因, List接口中沒有聲明fillrotateshuffleswap以及無限更多可能的列表函數。 他們不是在“名單”抽象的一部分; 相反,它們可以在該抽象之上實現。

一旦List實現了List接口中已有的方法,就可以在List抽象之上編寫一個reverse函數,而無需任何特定List實現的知識。 因此,強制每個實現List類都提供reverse的自定義實現(以及fillrotateshuffleswap等)是沒有意義的。

因為Collection是一個實用類,它實際上基於SOLID原則之一:
S - 單一職責原則

這個原則指出,如果我們有兩個理由改變一個類,我們必須將功能拆分為兩個類。

你有一個扮演某種角色的類,如果你需要操作內部數據,你需要創建一些子類,這將扮演另一個角色。

如果您需要list.reverse() ,則需要使用Eclipse Collections ,當您可以僅使用list.reverseThis() ,請參閱 在 JDK 列表中,很多方法(如 sort、max、min)沒有被添加。

這是兩種不同的 API 設計方式:

  1. Collection -> rich collection -> Eclipse Collections 中的很多方法,缺點:List 中很多很少使用的方法,
  2. 只有最常用的方法和實用程序類 -> JDK 集合,缺點:需要像集合一樣使用實用程序類,

注意:這個問題是“為什么 Collections 類包含獨立(靜態)方法,而不是將它們添加到 List 接口中?”的一個非常具體的案例。 - 甚至可以認為是重復。 除此之外,爭論為每個方法的決定背后的推理是閱讀茶葉,沒有人可以告訴了針對的具體情況設計決定“原因,” reverse法(直到,也許喬希布洛赫帖子這里的答案) . 有趣的是, Java 集合 API 設計常見問題解答中沒有涵蓋這一點......


其他一些答案乍一看似乎令人信服,但引發了其他問題。 特別是,其中一些根本沒有給出設計決策的理由。 即使有其他方法可以模擬某個方法的行為,或者當“99.9% 的時間”都沒有使用某個方法時,將它包含在界面中仍然有意義。


查看List接口,您會注意到您基本上可以基於另外兩個方法來實現所有方法:

  • T get(int index)
  • int size()

(對於可變列表,您還需要set )。 這些正是AbstractList中仍然抽象的那些。 所以所有其他方法都是相當“方便”的方法,可以基於這兩種方法規范地實現。 在這方面,我認為Sam Estep 的答案包含一個重要的觀點:人們可以爭論實施其他數十種方法。 這樣做肯定有充分的理由。 看看Collections#reverse(List)的實際實現:

public static void reverse(List<?> list) {
    int size = list.size();
    if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) {
        for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
            swap(list, i, j);
    } else {
        ListIterator fwd = list.listIterator();
        ListIterator rev = list.listIterator(size);
        for (int i=0, mid=list.size()>>1; i<mid; i++) {
            Object tmp = fwd.next();
            fwd.set(rev.previous());
            rev.set(tmp);
        }
    }
}

那里的REVERSE_THRESHOLDRandomAccess是什么東西? 說真的,如果我覺得有必要引入像RandomAccess這樣的標記界面,我會強烈質疑我的設計。 每當你有一個像

void doSomethingWith(Type x) {
    if (x instanceof Special) doSomethingSpecial((Special)x);
    else doSomethingNormal(x);
}

那么這是一個強烈的跡象,表明這實際上應該是一個多態方法,應該為Special類型相應地實現。


所以是的,將reverse方法拉入接口中是合理的,以允許多態實現。 這同樣適用於fill rotateshuffleswapsort等。 同樣,可以引入一個靜態方法,如

Collections.containsAll(containing, others);

它提供了現在使用Collection#containsAll方法所做的事情。 但總的來說:設計師選擇了一組他們認為合適的特定方法。 Java Collections API 的核心設計者之一Joshua Bloch 在關於“如何設計一個好的 API 以及為什么它很重要”的演講中提到了忽略某些方法的原因之一:

如有疑問,請忽略它

有趣的是,在所有多態實現(通過List接口中的方法)可能是合理的方法中,有一個實際上找到了進入接口的方法,使用 Java 8 default方法: List#sort() 也許其他人,如reverse ,將在以后添加......

反向在集合中定義(帶有額外的 (s))。 這不是集合層次結構的一部分,而是作為可用於不同列表的實用程序類的一部分。

反轉列表不是定義列表的關鍵部分,因此它被排除在接口之外並單獨給出。 如果在接口中定義,每個人都必須實現它,這可能不適合所有人。

集合的創建者也可以在 List 層次結構中構建它,(由於大多數列表派生之間都有一個抽象類,他們可以將它放在中間的任何抽象類中)。 然而,為了簡化每個人的生活,將它保存在單個實用程序類中是有意義的,這樣我們就不必弄清楚要查找所有與集合相關的實用程序函數的類。

暫無
暫無

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

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