-1

我们知道 Java 具有快速故障和故障安全的迭代设计。

我想知道,为什么我们基本上需要这些。这种分离有什么根本原因吗?. 这种设计有什么好处?

除了集合迭代之外,Java 在其他任何地方都遵循这种设计吗?

谢谢

4

1 回答 1

4

对于程序员来说,如果代码包含错误,则尽可能快地尝试失败是很有用的。最好的是在编译时,但有时这是不可能的。

因此,可以更早地检测到错误。否则,可能会发生错误仍未被发现,并且在您的软件中包含多年且没有人注意到该错误。

所以目标是尽早发现错误和错误。因此,接受参数的方法应该立即检查它们是否在允许的范围内,这将是迈向快速失败的一步。

这些设计目标无处不在,不仅仅是在迭代中,仅仅因为它是一个好主意。但有时您想在可用性或其他因素之间进行权衡。

例如,Set实现允许null值是许多错误的来源。新的 Java 9 集合不允许这样做,并在尝试添加此类时立即抛出异常,这是fail-fast


您的迭代器也是一个很好的例子。我们有一些快速失败的迭代器,它们不允许在迭代时修改集合。主要原因是因为它很容易成为错误的来源。因此他们抛出一个ConcurrentModificationException.

在迭代的特殊情况下,有人需要指定事情应该如何工作。当一个新元素在迭代过程中出现或被删除时,迭代应该如何表现?应该在迭代中包含/删除它还是应该忽略它?

例如,ListIterator提供了一个非常明确的选项来迭代List和操作它。在那里,您只允许操作迭代器当前所在的对象,这使其成为定义良好的对象。

另一方面,有一些故障安全迭代方法,例如使用ConcurrentHashMap. 它们不会抛出此类异常并允许修改。然而,他们在原始收藏的副本上工作,这也解决了“如何”的问题。因此地图上的更改不会反映在迭代器中,迭代器在迭代时完全忽略任何更改。这会增加成本,每次迭代都必须创建完整的副本。


就我个人而言,那些故障安全变体不是一种选择。我使用快速失败的变体并记住我想要操作的内容。迭代完成后,我执行那些记忆的操作。

这对程序员来说写起来不太舒服,但你可以获得fail-fast的优势。这就是我要权衡可用性的意思。

于 2017-08-16T12:59:33.267 回答