从scala异常中获取参数

时间:2018-02-07 15:38:08

标签: java scala exception arguments core

假设您在Scala(或Java)中有异常。如何在堆栈跟踪中获取方法的参数?

参数包含在诊断故障时非常有用的信息。唉,即使我相信他们仍然应该留在记忆中,我也认为无法获得它们。

catch(e) {
    x.getStackTrace.map(level => {
        // level has such methods as getClassName and getMethodName
        // but not the arguments.
        // Maybe the information is somewhere completely different?
        // In a Java equivalent of a core dump perhaps?
    })
}

1 个答案:

答案 0 :(得分:1)

你不能,至少不能正常执行程序。

当抛出异常时,堆栈将被解除"并在最近适用的" catch"恢复执行。块。堆栈中的任何数据(包括方法参数)都会丢失到程序中并立即可用于GC。

如果正在调试程序,那么可以在抛出异常时设置断点并检查调试器中的方法参数。 (您可以使用JVM代理实现相同的效果。)

您当然可以将方法参数传递给异常构造函数。

请参阅:

后续问题:我们可以改变Java来做这件事吗?

你说:

  

通过改变处理异常的方式 - 通过在展开前捕获信息,看起来好像有机会做到这一点。

然后

  

如何在JVM中分配堆栈?该方法的哪些细节使得很难获得参数?如果它类似于C中的堆栈那么对我来说,在执行异常处理程序之前必须放松是不明显的。处理程序不能在堆栈顶部运行,也不能在第二个堆栈中运行,而第一个堆栈具有查看权限?

正如我在下面提到的,我认为由于堆栈在标准JVM上的分配方式,这在不久的将来不太可能发生变化。你的两个建议的替代方案是好问题,我想让我们看看为什么使用当前的方法。

  1. 处理程序无法在堆栈顶部运行吗?
  2. 当然可以。这样做的主要缺点是每次处理异常时堆栈会增长很多。

    采用以下示例代码:

    public Foo computeFoo() {
      try {
        // 1
        return firstVersion();
      } catch (Exception e) {
        // 2
        return secondVersion();
      }
    }
    

    说我们到达了点#" 1"通过某种方法调用abc。堆栈帧堆栈可能看起来像:

    [ a, b, c, computeFoo ]
    

    让我们说firstVersion调用方法x,y,z,并在#34; z"内部抛出异常。抛出异常时,堆栈可能如下所示:

    [ a, b, c, computeFoo, firstVersion, x, y, z ]
    

    当我们转到第2点时,传统的JVM可以立即丢弃x,y,z中的所有数据,只需截断堆栈,然后再进入secondVersion

    [ a, b, c, computeFoo, secondVersion ]
    

    根据您的提议,JVM需要保留堆栈中x,y和z的堆栈帧数据,以防任何代码接近" 2"想要访问参数:

    [ a, b, c, computeFoo, firstVersion, x, y, z, secondVersion ]
    

    应该很清楚,一般来说,这可能会导致在使用异常的程序中将更多数据存储在堆栈中,而不是目前需要的。在JVM中还需要一些额外的簿记来处理"混合"堆栈的使用中和保留的堆栈帧,这将使维护变得复杂并减慢速度。

    鉴于a)异常通常不需要所有参数数据,b)在需要时可以轻松捕获特定参数数据,这里的当前标准权衡似乎更好。

    1. 处理程序无法在第二个堆栈中运行,而第一个堆栈具有查看权限吗?
    2. 当然,这可能会让JVM实施更多的工作,这会减慢一切,以获得不太引人注目的好处。因此目前的权衡。

      值得注意的是,这些系统不是从神灵传下来的,而是由人们设计的,是多年演变,建立共识和权衡的结果。 JVM工作的最重要原因之一是因为C ++曾经像这样工作,这是大多数人所期望和理解的。