我正在尝试理解Java标准集合库中的API不一致。
List或AbstractList中没有方法可以获取最后一项,尽管可以使用size和getIndex()来模拟它。
但是,LinkedList支持该功能。
知道为什么决定不在界面中支持这种方法吗?
答案 0 :(得分:19)
java.util.List
界面不支持getLast()
,因为设计师选择了“最小界面”。通过定义最少数量的方法,它可以更容易理解和更快地学习。
这与试图提供进行常见操作的方法(例如getLast()
)的“人性化界面”(例如在Ruby array class中使用的)形成对比。由于有很多用途可以将这样的基本概念作为列表,这往往会导致更大的接口。
有关详细信息,请参阅Martin Fowler的Minimal Interface和Humane Interface说明。
至于为什么LinkedList支持getLast()
等,引用javadoc:
... LinkedList类提供统一命名的方法来获取,删除和插入列表开头和结尾的元素。这些操作允许链表用作堆栈,队列或双端队列(双端队列)。
据推测,一般列表不适合这些特定用例。
作为对Java Collections API(Joshua Bloch)的主要设计者的思想的洞察,他提供了this list of API design maxims他的工作。其中,与此问题最相关的是:
API的早期草稿应该简短,通常是一个包含类和方法签名以及单行描述的页面。这样,当您第一次没有正确使用它时,可以轻松地重新构建API。
如有疑问,请将其删除。如果有一个API设计的基本定理,就是这样。它同样适用于功能,类,方法和参数。 API的每个方面都应尽可能小,但不能小一些。您可以随时添加内容,但不能将其删除。最小化概念权重比类或方法计数更重要。
保持API不受实现细节的影响。它们会混淆用户并抑制进化的灵活性。并不总是很清楚什么是实施细节:警惕过度规范。
尽量减少可访问性;如有疑问,请将其设为私有。这简化了API并减少了耦合。
考虑API设计决策的性能影响,但不要扭曲API以实现性能提升。幸运的是,良好的API通常适合快速实现。
然而他也说:
不要让客户做任何图书馆可以做的事情。违反此规则会导致客户端出现样板代码,这很烦人且容易出错。
这只是表明设计指南经常发生冲突,而API设计师工作中最难的部分就是平衡这些冲突。
答案 1 :(得分:5)
通常原因是他们想要指定具有Big-O要求的每个函数,并认为无法在所有列表上有效地实现getLast()。因此,他们以Big-O承诺在每个级别引入它。
或者它可能只是一个疏忽,或者他们觉得它不常见,如果你需要它,你可以用size / getIndex得到它。
答案 2 :(得分:2)
接口的目标是使用尽可能少的公共方法提供最大可用性。支持的方法越少越好。没有getLast()方法,因为这可以派生出来,如你所说。
另一方面,LinkedList是一个具体的实现,因此没有这些问题。编辑:正如Skaffman所指出的,这不是界面的主要目标。它更多的是次要目标,它允许更容易维护此接口的实现。接口的主要目的是将具体实现与使用它的对象分离。
答案 3 :(得分:1)
正如你所说,使用List,你可以使用getIndex()得到最后一个,因为它是基于索引的。所以我个人认为没有任何理由(因为你可以自己写)。
虽然LinkedList不是基于数组的,所以没有索引,提供类似的方法是有意义的,有时你需要知道最后一项。
答案 4 :(得分:1)
getLast()方法来自LinkedList实现的Deque接口。如果你想要一个阵列支持的版本,你可以使用ArrayDeque。我猜它不是List接口的一部分,因为他们希望将不同的抽象数据类型分离成单独的接口,即使像LinkedList这样的实现可以实现多个接口。
答案 5 :(得分:0)
getLast()无法在单向链表中实现。单向链表上的getIndex()可能会从头开始扫描整个列表,因此它具有效率意义。
答案 6 :(得分:0)
List接口没有该类型的任何便捷方法。没有getFirst()或getLast()。它严格基于索引。如果出于性能原因,LinkedList需要一种避免基于索引的查找的方法,因此getLast实际上是一种优化,而不是一种方便的方法。
我确信设计师希望减少方法的数量,因此他们没有添加许多可能方便的方法。