为什么Java的AbstractList类中的removeRange()方法是protected的?

114

有人知道为什么AbstractList(以及ArrayList)中的removeRange方法是protected吗?它看起来是一个非常明确和有用的操作,但是为了使用它,我们被迫子类化List实现。

是否有一些隐藏的理由?对我来说似乎相当难以理解。

1个回答

184

是的,因为那不是你从外部代码中删除范围的方法。相反,应该这样做:

list.subList(start, end).clear();

这实际上在后台调用了removeRange.


问题提出者问为什么removeRange不是List公共API的一部分。原因在于Effective Java第二版的第40条中描述,我在此引用:

有三种技术可以缩短过长的参数列表。其中之一是将方法拆分成多个子方法,每个子方法只需要参数的一个子集。如果处理不当,这可能会导致太多的方法,但它也可以通过增加正交性来帮助减少方法数量。例如,考虑java.util.List接口。它没有提供在子列表中查找元素的第一个或最后一个索引的方法,这两个方法都需要三个参数。相反,它提供了subList方法,它接受两个参数并返回子列表的视图。该方法可与indexOflastIndexOf方法结合使用,这两个方法都只有一个参数,以产生所需的功能。此外,subList方法可以与对List实例执行的任何方法组合,以在子列表上执行任意计算。由此产生的API具有非常高的功率重量比。

可以争辩removeRange没有那么多的参数,因此可能不是这种方法的候选者,但考虑到有一种通过subList调用removeRange的方式,没有理由在List接口中增加冗余的方法。


AbstractList.removeRange文档说:

该方法由clear操作在该列表及其子列表上调用。重写此方法以利用列表实现的内部机制可以显著地改善该列表及其子列表上的clear操作的性能。

另请参见OpenJDK的AbstractList.clearSubList.removeRange实现。


9
可以那样做,但是为什么?这似乎很别扭。单个元素可以直接从列表中移除,为什么不能同时移除多个元素呢? - Joonas Pulakka
22
+1 (问题已回答)。然而,仅仅因为给出了理由并不意味着它是合理的。缩短参数列表的过程阻碍了开发人员理解 API 中可用操作的能力,这直接违背了缩短列表的原因。 - Sam Harwell
6
很典型的Java。让它变得最复杂且最不有效率。 - Tomáš Zato
1
@vaxquis 请查看AbstractList.clearSubList.removeRange。 :-) - C. K. Young
2
顺便提一下,你是否注意到当使用ArrayList版本的范围跨越整个列表时,removeRange不必要地调用了arraycopy?http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/e2117e30fb39/src/share/classes/java/util/ArrayList.java#l631 numMoved为0,因此整个arraycopy代码可以放入单个if中(与remove中所做的相同);区别在于a)arraycopy是本机调用,会产生开销,b)`arraycopy总是检查参数的正确性。 https://dev59.com/x2cs5IYBdhLWcg3ww2tP - user719662
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接