繁体   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