Java 允许您创建一个全新的 Throwable
子类型,例如:
public class FlyingPig extends Throwable { ... }
现在,很少,我可能会这样做:
throw new FlyingPig("Oink!");
当然还有其他地方:
try { ... } catch (FlyingPig porky) { ... }
我的问题是:
- 这是个坏主意吗?如果是这样,为什么?
- 如果这是一个坏主意,可以做些什么来防止这种子类型化?
- 既然无法预防(据我所知),可能会导致什么灾难?
- 如果这不是一个坏主意,为什么不呢?
- 您可以
extends Throwable
这一事实如何做出有用的东西?
- 您可以
提议的场景 #1
我真的想要做这样的事情的场景具有以下属性:
- “事件”是将最终发生的事情。这是预期的。它绝对不是
Error
,也没有关于它何时发生的Exception
。- 因为是意料之中的,所以会有一个
catch
在等它。它不会“溜走”任何东西。它不会“逃避”任何catch
一般Exception
和/或Error
的尝试。
- 因为是意料之中的,所以会有一个
- “事件”发生极少。
- 发生这种情况时,通常会有很深的堆栈跟踪。
所以现在我想说的可能很清楚了:FlyingPig
是穷举递归搜索的结果。
要搜索的对象存在:只要在搜索空间的大海中找到它。搜索过程将是一个漫长的过程,因此异常处理相对昂贵的成本可以忽略不计。事实上,使用 boolean isFound
标志的传统控制流构造替代方案可能更昂贵,因为它必须在整个搜索过程中不断检查,很可能在递归的每个级别。此检查将在 99.99% 的情况下失败,但传播终止条件是绝对必要的。在某种程度上,虽然有效,但检查效率低下!
通过简单地 throw
-ing 一个 FlyingPig
找到所寻找的对象,您不必使用 boolean isFound 的管理来弄乱代码
标志。不仅在这方面代码更干净,而且由于这个遗漏,它可能运行得更快。
总而言之,选择是在这两者之间:
- 传统的控制流方法
- 使用
boolean isFound
,不断检查 - 99.99% 的情况下,支票是“浪费”,因为它仍然是
false
- 当它最终变为
true
时,您将停止递归,您必须确保可以正确地展开到初始调用。
- 使用
飞 pig
方法- 不要为任何
boolean isFound
烦恼。 - 如果找到,只需
throw new FlyingPig()
;这是预期的,所以会有一个catch
。 - 不管理
boolean
标志,不浪费检查是否需要继续,不记录手动展开递归等。
- 不要为任何
问题:
- 这种(ab)使用异常的技术是否有效? (有名字吗?)
- 如果有效,应该
FlyingPig extends Throwable
,还是Exception
就好了? (即使它的情况并没有什么特别之处?)
最佳答案
我会说这是一个非常糟糕的主意。很多代码的实现都假设如果你捕获了 Error
和 Exception
你已经捕获了所有可能的异常。大多数教程和教科书都会告诉你同样的事情。通过创建 Throwable
的直接子类,您可能会产生各种维护和互操作性问题。
我想不出扩展 Throwable
的充分理由。改为扩展 Exception
或 RuntimeException
。
编辑 - 响应 OP 提出的方案 #1。
异常是处理“正常”流控制的一种非常昂贵的方法。在某些情况下,我们正在谈论 数千 条额外的指令来创建、抛出和捕获异常。如果您要忽略公认的智慧并使用异常进行非异常流控制,请使用 Exception
子类型。试图通过将 is 声明为 Throwable
的子类型来假装某事是“事件”而不是“异常”是不会取得任何成果的。
但是,将异常与错误、错误、错误等混为一谈是错误的。并且使用 Exception
的子类来表示“不是错误、错误、错误或其他的异常事件”没有错。关键是事件要异常;即不寻常,很少发生,...
总而言之,FlyingPig
可能不是错误,但这不是不将其声明为 Exception
的子类型的理由。
关于java - 在 Java 中扩展 Throwable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2755972/