为什么Java中没有"List.reverse()"方法?

Han*_*Sun 9 java oop interface list

在Java中,为了反转List中的元素,我需要使用:

Collections.reverse(list)
Run Code Online (Sandbox Code Playgroud)

我只是想知道为什么Java没有在List接口中实现反向方法,所以我可以这样做就地反向:

list.reverse()
Run Code Online (Sandbox Code Playgroud)

有没有人对此有任何想法?

Ste*_*n C 10

为什么List.reverse()Java中没有方法?

因为有一种Collections.reverse(List)方法.

因为API设计者认为强制每个 List实现1实现一个99.9%的时间未使用的方法是一个坏主意2.这可以通过使方法"可选"来解决,但这也有缺点; 例如运行时异常.

因为对于某些类型的列表(例如流包装器/适配器),实现就地反向会有问题.它通过要求对其进行修改来更改列表的内存使用特性.

另请注意,通用实现(源代码)reverse()由交换元素的Collection用途提供set.它接近标准列表类型的最佳值.


@shmosel评论:

我假设OP问为什么它没有作为默认方法添加,就像List.sort()那样.

好问题.可能99.9%的论点适用.请记住,这只会帮助拥有使用Java 8或更高版本编译器等构建的代码库的人.


1 - 这包括代码库和第三方库中的实现.

2 - 86%的统计数据用于戏剧效果:-)


Sam*_*tep 6

出于同样的原因,fillrotateshuffleswap和无限可能的更多的功能列表中未声明的List接口.他们不是部分的"列表"抽象的; 相反,它们可以在该抽象之上实现.

一旦List实现了List接口中已有的方法,reverse就可以在List抽象之上编写函数,而无需了解特定的List实现.因此,这将是毫无意义的,迫使每一个类实现List提供的自定义实现reverse(和fill,rotate,shuffle,swap,等).


Mar*_*o13 5

注意:这个问题是“为什么 Collections 类包含独立(静态)方法,而不是将它们添加到 List 接口?”的一个非常具体的案例。- 人们甚至可以将其视为重复项。除此之外,争论每个单独方法的决策背后的推理就像读茶叶一样,没有人能说出该方法的特定情况的设计决策的“原因” reverse直到,也许乔什·布洛赫(Josh Bloch)在这里发布了答案)。有趣的是,这一点在Java Collections API Design FAQ中没有涉及到......


其他一些答案乍一看似乎很有说服力,但也提出了其他问题。特别是,其中一些根本没有给出设计决策的理由。即使有其他方法来模拟某个方法的行为,或者当“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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

REVERSE_THRESHOLD这个和那里的东西是什么RandomAccess?说真的,如果我觉得有必要引入像 一样的标签界面RandomAccess,我会强烈质疑我的设计。每当你有像这样的方法

void doSomethingWith(Type x) {
    if (x instanceof Special) doSomethingSpecial((Special)x);
    else doSomethingNormal(x);
}
Run Code Online (Sandbox Code Playgroud)

那么这是一个强烈的信号,表明这实际上应该是一个多态方法,应该针对该Special类型相应地实现。


reverse因此,是的,将方法拉入接口中以允许多态实现是合理的。这同样适用于fill rotateshuffleswapsort和其他。同样,我们可以引入一个静态方法,例如

Collections.containsAll(containing, others);
Run Code Online (Sandbox Code Playgroud)

这提供了现在使用该方法所做的事情Collection#containsAll。但总的来说:设计师选择了一套他们认为合适的特定方法。省略某些方法背后的原因之一可能是Joshua Bloch (Java Collections API 的核心设计者之一)关于“如何设计一个好的 API 及其重要性”的演讲的底线之一:

如有疑问,请忽略它

List有趣的是,在所有合理的多态实现(通过接口中的方法)的方法中,有一个实际上使用 Java 8 方法找到了进入接口的default方式:List#sort()。也许其他的,比如reverse,稍后会添加......