在Java中,要反转List中的元素,我需要使用:
Collections.reverse(list)
我只是想知道为什么Java没有在List
接口中实现反向方法,所以我可以像这样进行就地反转:
list.reverse()
有没有人对此有任何想法?
答案 0 :(得分:10)
为什么Java中没有
List.reverse()
方法?
因为有Collections.reverse(List)
方法。
因为API设计人员认为强制每个 List
实现 1 来实现一个未使用99.9%的方法是一个坏主意。时间 2 。这可以通过使方法“可选”来解决,但这也有缺点;例如运行时异常。
因为对于某些类型的列表(例如流包装器/适配器),实现就地反向会有问题。它通过要求对其进行修改来更改列表的内存使用特性。
另请注意,reverse()
提供的Collection
的通用实现(source code)使用set
来交换元素。它接近标准列表类型的最佳值。
@shmosel评论:
我假设OP问为什么它没有作为默认方法添加,因为List.sort()是。
好问题。可能99.9%的论点适用。请记住,这只会帮助拥有使用Java 8或更高版本编译器等构建的代码库的人。
1 - 这包括代码库和第三方库中的实现。
2 - 86%的统计数据用于戏剧效果:-)
答案 1 :(得分:6)
出于同样的原因Leaky RELU和fill
以及rotate
和shuffle
以及无法更多可能的列表函数未在List
接口中声明。它们不是“列表”抽象的部分;相反,它们可以在那个抽象的基础上实现。
一旦List
实现了List
接口中已有的方法,reverse
函数就可以在List
抽象之上编写,而不需要了解特定的List
{1}}实施。因此,强制每个实现List
的类提供reverse
(和fill
,rotate
,shuffle
,{{1}的自定义实现是毫无意义的。等等。)。
答案 2 :(得分:4)
因为Collection
是一个功利主义阶级,实际上是基于documentation原则之一: S - 单一责任原则
这个原则指出,如果我们要为一个类改变 2个原因,我们必须将功能分成两个类。
你有一个扮演某个角色的类,如果你需要操作内部数据,你需要创建一些辅助类,这将扮演另一个角色。
答案 3 :(得分:3)
如果您需要list.reverse()
,则需要使用Eclipse Collections,当您只使用list.reverseThis()
时,请参阅this。在JDK列表中,不添加许多方法(如sort,max,min)。
这是API设计的两种不同方式:
答案 4 :(得分:3)
注意:这个问题是"Why does the Collections class contain standalone (static) methods, instead of them being added to the List interface?"的一个非常具体的案例 - 人们甚至可以认为是重复的。除此之外,争论每个方法的决策背后的推理是阅读茶叶,没有人可以为reverse
方法的特定情况的设计决策告诉“ 原因” (直到,也许Josh Bloch在这里发布了答案)。有趣的是,这是Java Collections API Design FAQ ...
其他一些答案乍一看似乎令人信服,但提出了其他问题。特别是,其中一些根本没有给出设计决定的理由。即使有其他方法可以模拟某种方法的行为,或者某种方法没有被“99.9%的时间”使用,但将它包含在界面中仍然有意义。
查看List
界面,您会发现基本上可以基于另外两个方法实施所有方法:
T get(int index)
int size()
(对于可变列表,您还需要set
)。这些正是AbstractList
中仍然是抽象的。所以所有其他方法都是相当“方便”的方法,可以基于这两种方法规范地实现。在这方面,我认为the answer 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_THRESHOLD
和RandomAccess
的内容是什么?说真的,如果我觉得有必要引入像RandomAccess
这样的标记界面,我会强烈质疑我的设计。只要你有像
void doSomethingWith(Type x) {
if (x instanceof Special) doSomethingSpecial((Special)x);
else doSomethingNormal(x);
}
然后这是一个强符号,这实际上应该是一个多态方法,应该针对Special
类型进行相应的实现。
所以是的,将reverse
方法拉入接口是合理的,以允许多态实现。这同样适用于fill
rotate
,shuffle
,swap
,sort
等。同样,人们可以引入静态方法,如
Collections.containsAll(containing, others);
提供了Collection#containsAll
方法现在所做的事情。但总的来说:设计师选择了一组他们认为合适的特定方法。遗漏某些方法的原因之一可能是Java集合API的核心设计者之一the talk about "How to Design a Good API & Why it Matters" by Joshua Bloch的底线之一:
有趣的是,在多态实现(通过List
接口中的方法)可能合理的所有方法中,一个实际上已经进入接口,使用Java 8 default
方法:List#sort()
。也许其他人,比如reverse
,稍后会添加......
答案 5 :(得分:0)
反转在集合中定义(带有额外的(s))。这不是集合层次结构的一部分,而是作为实用程序类的一部分给出,可用于不同的列表。
反转列表不是定义列表的关键部分,因此它不受界面限制并单独给出。如果在界面中定义,每个人都必须实现它,这可能不适合所有人。
集合的制作者也可以在List层次结构中构建它,(因为大多数列表派生之间都有一个抽象类,它们可以将它放在其间的任何抽象类中)。但是,为了简化每个人的生活,将它保存在单个实用程序类中是有意义的,这样我们就不必弄清楚要查找所有与集合相关的实用程序函数的类。