在 Java 中始终抛出相同的异常实例

2022-09-04 07:37:07

人们总是告诉我,Java异常处理非常昂贵。

我在问,在程序开始时创建特定类型的异常实例,而不创建一个新实例,总是抛出相同的异常对象,这是否是一种很好的做法。

我只想举个例子。常用代码:

if (!checkSomething(myObject))
   throw new CustomException("your object is invalid");

另类:

static CustomException MYEXP = new CustomException("your object is invalid");

//somewhere else
if (!checkSomething(myObject))
    throw MYEXP;

当然,我在这里做了一些假设:

  1. MyCustomException没有参数
  2. 无论何时是一种好的做法,客户端代码都是基于异常处理,重构不是一种选择。

所以问题是:

  1. 这是一种很好的做法吗?
  2. 这会损坏某些 JVM 机制吗?
  3. 如果 1 是 yes,是否有可能提高性能?(我认为不是,但不确定)
  4. 如果1和3是肯定的,为什么不作为实践赞助?
  5. 如果1不是,为什么马丁·奥德斯基(Martin Odersky)在Scala的介绍中告诉Scala,在某些情况下这就是Scala的工作方式?(在第28.30分钟,他告诉break的实现会引发异常,观众说这很耗时,他回答说不是每次都创建异常)福斯德姆 2009

我希望这不是一个无聊/愚蠢的问题,我对此感到好奇。我认为异常处理的真正成本是处理而不是创建。

编辑增加了对FOSDEM演示的精确讨论的参考

免责声明:我的代码都不像提议的那样工作,我无意管理这样的异常,我只是在做一个“假设”问题,这种好奇心是由该视频的传出而产生的。我想:如果它是在Scala中完成的,为什么不是在Java中完成的呢?


答案 1

不,不要那样做。昂贵的部分不是处理异常,而是生成堆栈跟踪。不幸的是,堆栈跟踪也是有用的部分。如果抛出已保存的异常,则会传递误导性的堆栈跟踪。

在Scala的实现中,在某些情况下,这样做可能是有意义的。(也许他们正在做一些递归的事情,并希望预先生成一个异常对象,所以如果他们的内存不足,他们仍然可以产生一个异常。他们也有很多关于他们正在做的事情的信息,所以他们有更好的机会把它做好。但是JVM语言实现者所做的优化是一个非常特殊的情况。

因此,除非您认为提供误导性信息构成破坏,否则您不会破坏任何东西。这对我来说似乎是一个很大的风险。

尝试 Thomas Eding 关于如何创建没有堆栈跟踪的异常的建议似乎有效:

groovy:000> class MyException extends Exception {
groovy:001>     public Throwable fillInStackTrace() {}}
===> true
groovy:000> e = new MyException()
===> MyException
groovy:000> Arrays.asList(e.stackTrace)
===> []

另请查看 JLS

由方法 blowUp 引发的 NullPointerException(一种 RuntimeException)不会被 main 中的 try 语句捕获,因为 NullPointerException 不能分配给 BlewIt 类型的变量。这会导致 finally 子句执行,之后执行 main(测试程序的唯一线程)的线程将由于未捕获的异常而终止,这通常会导致打印异常名称和简单的回溯。但是,此规范不需要回溯。

强制执行回溯跟踪的问题在于,可以在程序中的某个点创建异常,然后在以后的某个点引发异常。将堆栈跟踪存储在异常中的成本非常高昂,除非它实际上被抛出(在这种情况下,跟踪可能会在展开堆栈时生成)。因此,我们不会要求在每个异常中都进行回溯跟踪。


答案 2

问题 1.这是一种很好的做法吗?

不在我的书中。它增加了复杂性并阻碍了诊断(请参阅我对Q2的回答)。

问题 2.这会损坏某些 JVM 机制吗?

您不会从此类异常对象获得有意义的堆栈跟踪。

问题 3.如果 1 是肯定的,那么性能是否有收益?(我认为不是,但不确定)

问题 4.如果1和3是肯定的,为什么不作为实践赞助?

由于上述问题。

问题 5.如果1不是,为什么马丁·奥德斯基(Martin Odersky)在Scala的介绍中告诉Scala,在某些情况下这就是Scala的工作方式?(抱歉,但我现在不记得这个肯定的背景)福斯德姆 2009

没有上下文很难回答。


推荐