为什么我们需要快速失败并且安全软件设计失败?

时间:2017-08-16 12:49:20

标签: java collections iterator fail-fast

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

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

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

由于

1 个答案:

答案 0 :(得分:4)

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

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

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

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

作为示例,Set实现允许null值,这是许多错误的来源。新的Java 9集合不允许这样做,并在尝试添加时立即抛出异常,这是快速失败

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

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

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

另一方面,有一些故障安全迭代方法,例如使用ConcurrentHashMap。他们不会抛出这些例外并允许修改。但是,他们处理原始集合的副本,这也解决了“ how ”问题。因此,迭代器中反映的地图上的更改,迭代器在迭代时完全忽略任何更改。这会增加成本,每次迭代时都必须创建完整的副本。

对我个人而言,自动防故障变体不是一种选择。我使用 fail-fast 变体并记住我想要操作的内容。迭代完成后,我执行那些记忆的操作。

这对程序员来说不太舒服,但你可以获得快速失败的优势。这就是我的意思,与可用性进行权衡。