单例异常是否有效?

时间:2009-04-17 21:48:35

标签: java exception static singleton

我的一位同事在工作中介绍了静态工厂方法(在Effective Java之外),然后给出了一个用于获取静态/单例异常的示例。

这给我带来了一面红旗。有例外是否有状态?它们不是由JVM填充堆栈跟踪信息吗?你真正得到了什么节省,因为异常应该仅在特殊情况下发生?

我对异常的了解相当有限,所以我带着这个来找你:单例异常是否有效,是否有理由使用它们?

4 个答案:

答案 0 :(得分:17)

单例异常应该是性能优化。我们的想法是在创建异常时消除填充堆栈跟踪的成本,这通常是异常中最昂贵的部分。

如果异常足够独特且具有描述性并且不会使用堆栈跟踪,那么单例可能会有效。您可以设计应用程序,使具有特定消息的特定异常类型始终表示从特定位置开始的异常。然后堆栈跟踪将无关紧要。

April 22, 2003 Tech Tips article描述了重用异常的场景。在这种情况下,他们试图通过减少创建的对象数来对垃圾收集器进行游戏。如果您跳过populateStackTrace()电话,则无需担心线程。

通常,如果异常的性能影响导致问题,则表示异常正在用于应用程序逻辑,而应使用错误代码。

在较新的JVM(1.4+,我相信)中,这种“优化”可以在“-server”模式下运行时由JVM自动完成。此热点优化可以通过选项-XX:+OmitStackTraceInFastThrow控制。

就个人而言,我建议不要使用单例异常[反]模式。

答案 1 :(得分:3)

虽然我衷心地不同意这种方法,但Singleton Exceptions 可以在单线程环境中工作。

建议使用Singleton Exception模式的人倾向于使用旧的c风格调用/错误/检查错误范例,并希望将其转换为其中一种新的“面向对象”语言。

这是可能的,但我称之为代码味道。

答案 2 :(得分:1)

我可以想象一种情况,在这种情况下,您希望能够在异常条件中检测到应用程序的其他部分是否已经抛出异常;我可以看到为这种目的使用单例异常;但这似乎有点多余。从本质上讲,它将信号量(“发生的事情”)的概念与异常(“发生在我身上的事情”)混为一谈。

答案 3 :(得分:0)

如果“静态工厂方法”不断返回同一个对象,则它实际上不是工厂方法。

偶数java.lang.Throwable有两个可变状态项:堆栈跟踪和初始原因,直到新版本的Java添加更多。任何共享Throwable都需要违反fillInStackTrace的合同或行为非常奇怪。此外,重用的Throwable无法合理地更改消息。

所以你可以侥幸逃脱,但你想要吗?几乎所有的性能问题(通常不应该经常抛出异常)都归结为fillInStackTrace。如果你敲出来那么重用就没有意义了。

(我更喜欢“静态创建方法”到“静态工厂方法”这个短语,因为“工厂”太过分了。)