在Java中扩展Throwable

pol*_*nts 28 java exception-handling throwable

Java允许您创建一个全新的子类型Throwable,例如:

public class FlyingPig extends Throwable { ... }
Run Code Online (Sandbox Code Playgroud)

现在,很少,我可以这样做:

throw new FlyingPig("Oink!");
Run Code Online (Sandbox Code Playgroud)

当然还有其他地方:

try { ... } catch (FlyingPig porky) { ... }
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  • 这是一个坏主意吗?如果是这样,为什么?
    • 如果这是一个坏主意,可以做些什么来阻止这种子类型?
    • 由于它不可预防(据我所知),可能导致什么灾难?
  • 如果这不是一个坏主意,为什么不呢?
    • 你怎么能从事可以做出有用的事情extends Throwable

拟议方案#1

真的想做这样的事情的场景具有以下属性:

  • "事件" 最终发生.这是预料之中的.它绝对不是一个Error,而且它什么也没Exception发生.
    • 因为它是预期的,所以会有一个catch等待它.它不会"滑倒"过去.它不会"逃避"任何catch一般Exception和/或任何尝试Error.
  • "事件" 极少发生.
  • 当它发生时,通常会有一个深层堆栈跟踪.

所以也许我现在很清楚我想说的FlyingPig是:这是一个详尽的递归搜索的结果.

要搜索的对象存在:它只是在大海中找到它的问题,即搜索空间.搜索过程很长,因此相对昂贵的异常处理成本可以忽略不计.事实上,传统的控制流构造使用boolean isFound标志的替代方案可能更昂贵,因为必须在整个搜索过程中连续检查,最有可能在递归的每个级别.此检查将在99.99%的时间内失败,但绝对有必要传播终止条件.在某种程度上,虽然有效,但检查效率低下!

通过简单的throw-ing一FlyingPig当试图找到对象,你不必与管理杂波的代码boolean isFound标志.在这方面,代码不仅更清洁,而且由于这种遗漏,它可能运行得更快.

总而言之,选择是在这两者之间:

  • 传统的控制流方法
    • 使用a boolean isFound,连续检查
    • 99.99%的时间,支票是"浪费",因为它仍然是 false
    • 当它最终成为时true,你停止递归,你必须确保你可以正确地放松到初始调用.
  • FlyingPig 途径
    • 不要打扰任何boolean isFound.
    • 如果发现,只是throw new FlyingPig(); 它是预期的,所以会有一个catch它.
    • 没有管理boolean标志,没有浪费检查你是否需要继续前进,没有簿记来手动解除递归等.

问题:

  • (ab)这种技术使用异常是否有效?(有名字吗?)
  • 如果有效,应该FlyingPig extends Throwable或是Exception好吗?(即使它的情况没有什么特别之处?)

Ste*_*n C 32

我会说这是一个非常糟糕的主意.很多代码都是基于这样的假设实现的:如果你抓住Error并且Exception你已经捕获了所有可能的异常.大多数教程和教科书都会告诉你同样的事情.通过创建直接子类,Throwable您可能会创建各种维护和互操作性问题.

我认为没有充分理由延长Throwable.延伸ExceptionRuntimeException代替.

编辑 - 响应OP提议的场景#1.

例外是处理"正常"流量控制的一种非常昂贵的方式.在某些情况下,我们正在讨论为执行创建,抛出和捕获异常而执行的数千条额外指令.如果您要忽略已接受的智慧并使用异常进行非异常流量控制,请使用Exception子类型.试图假装某事是一个"事件",而不是一个"例外",宣称它是一个Throwable不会实现任何目标的子类型.

但是,将异常与错误,错误,错误等混淆是错误的.并没有什么错与表示"特殊事件不是错误,错,错,或任何"使用的子类Exception.关键是该活动应该是特殊的 ; 即不寻常的,很少发生,......

总之,a FlyingPig可能不是错误,但没有理由不将其声明为子类型Exception.

  • @Stephen Denne - 在10年多的Java编码中,我还没有遇到过将Throwable扩展为一个好主意的情况.当然,这种情况可能存在并非不可能...... (5认同)
  • @polygenelubricants - 用例对于异常听起来是合理的,特别是如果它**也显着简化了代码. (2认同)

Pas*_*ent 8

(ab)这种技术使用异常是否有效?(有名字吗?)

在我看来,这不是一个好主意:

  • 它违反了最不惊讶原则,它使代码更难以阅读,特别是如果没有任何异常的话.
  • 抛出异常在Java中是一个非常昂贵的操作(虽然这可能不是问题).

不应异常用于流量控制.如果我不得不说出这种技术,我会把它称为代码气味或反模式.

也可以看看:

如果有效,应该FlyingPig延长Throwable,还是Exception很好?(即使它的情况没有什么特别之处?)

在某些情况下,您不仅要捕获 Throwable,Exception 而且还要 捕获,Error很少见,人们通常不会捕获Throwable.但是我找不到你想抛出一个子类的情况Throwable.

而且我也认为延伸Throwable不会让事情看起来不那么"异常",它们会使它看起来更糟 - 这完全打败了意图.

总而言之,如果你真的想扔东西,抛出一个子类Exception.

也可以看看:


rjw*_*rjw 7

以下是来自HotSpot架构师John Rose的博客文章:

http://blogs.oracle.com/jrose/entry/longjumps_considered_inexpensive

它是关于流量控制的"滥用"例外.稍微不同的用例,但是..简而言之,它工作得非常好 - 如果您预先分配/克隆您的异常以防止创建堆栈跟踪.

我认为如果从客户那里"隐藏",这种技术是合理的.IE,你的FlyingPig永远不能离开你的图书馆(所有公共方法都应该保证不丢弃它).保证这一点的一种方法是使其成为一个经过检查的例外.

我认为扩展Throwable的唯一理由是因为你想允许人们传递具有catch(Exception e)子句的回调,并且希望你的结果被他们忽略.我只能买那个......