我们知道Java具有故障快速和故障安全的迭代设计。
我想知道,为什么我们基本上需要这些。这种分离有什么根本原因吗?.这种设计有什么好处?
除了集合迭代,Java在其他任何地方都遵循这种设计?
谢谢
对于程序员来说,如果代码包含错误,则尝试尽快失败是很有用的。最好的是在编译时,但这有时是不可能的。
因此,可以更早地检测到错误。否则,可能会发生错误仍未检测到并且包含在您的软件中多年并且没有人注意到该错误的情况。
因此,目标是尽早检测错误和错误。因此,接受参数的方法应立即检查它们是否在允许的范围内,这将是迈向快速失败的一步。
这些设计目标无处不在,而不仅仅是迭代,仅仅因为它是一个好主意。但有时您想在可用性或其他因素之间进行权衡。
例如,Set
实现允许null
值,这是许多错误的来源。新的 Java 9 集合不允许这样做,并且在尝试添加此类集合时会立即抛出异常,这是快速失败的。
您的迭代器也是一个很好的例子。我们有一些快速失败迭代器,它们不允许在迭代集合时修改集合。主要原因是因为它很容易成为错误的根源。因此,他们抛出了ConcurrentModificationException
.
在迭代的特殊情况下,有人需要指定事情应该如何工作。当迭代时出现或删除新元素时,迭代应该如何表现?应该在迭代中包含/删除它还是应该忽略它?
例如,ListIterator
提供了一个定义非常明确的选项来迭代List
并对其进行操作。在那里,您只允许操作迭代器当前所在的对象,这使得它定义良好。
另一方面,有一些故障安全迭代方法,例如使用ConcurrentHashMap
.它们不会引发此类异常并允许修改。然而,他们正在处理原始收藏的副本,这也解决了">如何"的问题。因此,地图上的更改不会反映在迭代器中,迭代器在迭代时完全忽略任何更改。这会增加成本,每次迭代时都必须创建一个完整的副本。
就我个人而言,这些故障安全变体不是一种选择。我使用快速故障变体并记住我想要操作的内容。迭代完成后,我执行那些记忆的操作。
对于程序员来说,这不太舒服,但您可以获得快速失败的优势。这就是我所说的权衡可用性的意思。