为什么Throwable.fillInStackTrace()方法公开?为什么会有人使用它?

Dan*_*lor 33 java exception

我很好奇,为什么是方法fillInStackTracejava.lang.Throwable公开?

此方法将原始堆栈跟踪替换为调用它的位置,删除本地化异常所需的信息.它可以用于混淆,但不需要太多努力,因为新的堆栈跟踪将指向混淆代码.更好的方法是简单地隐藏异常或抛出异常.

但我无法找到在现有方法上调用此方法的任何合理案例Throwable.所以问题是:为什么这种方法是公开的?背后有什么意义吗?

sbr*_*ges 44

一个原因是表现.投掷和捕捉异常很便宜; 昂贵的部分填充堆栈跟踪.如果覆盖fillInStackTrace()不执行任何操作,则创建异常也会变得很便宜.

除了便宜的例外,您可以使用流控制的异常,这可以使代码在某些情况下更具可读性; 您可以在实现需要更高级流控制的 JVM语言时使用它们,如果您正在编写actor库,它们非常有用.

  • 但是`protected`会对这个用例起作用. (4认同)
  • 我怀疑这种用法是设计师的意图 (3认同)

jta*_*orn 20

一个可能合法的用途是在与实际投掷的地方不同的地方创建例外.例如,您可能有一个应用程序,您可以在其中提供用于生成自定义异常的插件工具.由于堆栈跟踪在构造中被填充,因此异常的跟踪将包括可能具有误导性的信息(它将包括对自定义异常工厂的调用).因此,您的应用程序将在自定义工厂生成调用fillInStackTrace()异常,以便为异常的最终接收者提供更准确的堆栈跟踪.

这个被拒绝的错误表明你不是唯一一个对这种方法需要困惑的人.


Chr*_*rle 5

Throwable.fillInStackTrace()的一个合法用例是非本地控制流:

例如,在我的TrueZIP框架中,我使用复杂的装饰器链来存储文件系统控制器.该链中的一个控制器是类FsLockController的一个实例.该对象负责管理文件系统的ReentrantReadWriteLock.现在,此链中更深处的文件系统控制器可能检测到需要写锁定,但FsLockController仅获取了读锁定.因为在没有死锁的情况下无法将读锁升级为写锁,所以必须抛出异常,这恰好是类FsNeedsWriteLockException的一个实例.然后,装饰FsLockController将捕获此异常,释放读锁并获取写锁,然后再次重试该操作.

这种非本地控制流程实际上非常有效,但有一点需要考虑:抛出和捕获异常很便宜,但填写或检查其堆栈跟踪是很昂贵的.现在因为这个特殊的异常类型是在这个文件系统控制器链中单独抛出和捕获的,所以我根本不需要堆栈跟踪,因此我可以安全地使用空方法体覆盖Throwable.fillInStackTrace()以抑制这种昂贵的操作.

可以在此处看到此异常类型的基类的源代码.