为什么我们需要快速故障和故障安全软件设计?

Why we need fail fast and fail safe software design?

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

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

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

谢谢

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

因此可以更早地检测到错误。否则,可能会发生一个错误未被发现并在您的软件中存在多年而没有人注意到该错误的情况。

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

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

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


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

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

例如,ListIterator 提供了一个非常 定义明确的 选项来迭代 List 并对其进行操作。在那里你只能操作迭代器当前所在的对象,这使得它 well-defined.

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


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

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