【问题标题】:jvm exception catchingjvm异常捕获
【发布时间】:2012-03-31 08:53:17
【问题描述】:

所以我最近写了一个扩展异常的java类,并使用该类的一个实例来检查案例并在发生错误时自行抛出。我发现当 main 的调用者捕获到这个异常时,它说异常被抛出的那一行是异常被创建的那一行,而不是它被抛出的那一行。我只是想知道为什么会这样,以及它是否是 jvm 的预期行为,因为这不是引发异常的常见方式。如果这是预期的行为,那么这样做的原因是什么,因为似乎引发异常的行号会更有用(并且可能更容易通过堆栈进行跟踪)。示例案例展示了预期行为和意外行为。


正常抛出异常:

1  public class Test
2  {
3   public static void main(String ... args) throws Throwable
4   {
5       switch(5)
6       {
7           case 1: throw new Exception("Exception");
8           case 2: throw new Exception("Exception");
9           case 3: throw new Exception("Exception");
10          case 4: throw new Exception("Exception");
11          case 5: throw new Exception("Exception");
12      }
13  }
14 }

输出:

Exception in thread "main" java.lang.Exception: Exception
    at Test.main(Test.java:11)

我的方法(简化):

1  public class Test
2  {
3   public static void main(String ... args) throws Throwable
4   {
5       Exception e = new Exception("Exception");
6       switch(5)
7       {
8           case 1: throw e;
9           case 2: throw e;
10          case 3: throw e;
11          case 4: throw e;
12          case 5: throw e;
13      }
14  }
15 }

输出:

Exception in thread "main" java.lang.Exception: Exception
    at Test.main(Test.java:5)

【问题讨论】:

    标签: java debugging exception-handling jvm


    【解决方案1】:

    它说异常被抛出的那一行是从哪里开始的那一行 异常是创建的,而不是从哪里引发的。我只是 想知道为什么会这样,以及它是否是 jvm 的预期行为 与否

    是的。它不仅是预期的,而且是记录在案的。请参阅java.lang.Throwable 的 Javadoc:“可抛出对象包含其线程在创建时的执行堆栈的快照。”如果你不想这样,你可以选择在扔之前打电话给fillInStackTrace()

    【讨论】:

      【解决方案2】:

      来自JavaDoc for Throwable

      通常,这是创建此 throwable 的点,并且 扔了。

      这有点模棱两可,但 99% 的情况下,异常是在引发异常时创建的。我想当您考虑重新抛出异常时,从创建点创建堆栈跟踪更有意义,例如:

      void bar() throws Exception
      {
          throw Exception();
      }
      
      void foo() throws Exception
      {
          try
          {
              bar();
          }
          catch (Exception e)
          {
              throw e;
          }
      }
      
      public static void main(String[] args)
      {
         foo();
      }
      

      知道异常是在bar() 中创建的,比知道它是在foo() 中重新抛出的更有用。如果此信息很重要,您可以抛出一个新异常,并将原始异常作为原因参数。

      更新

      为了说明,如果您真的想知道在 foo() 中也引发了异常,那么您可以在 foo() 中执行此操作

      void foo() throws Exception
      {
          try
          {
              bar();
          }
          catch (Exception e)
          {
              throw new Exception("Some more useful information from foo", e);
          }
      }
      

      【讨论】:

      • 但在您的示例中,您在创建异常的同时抛出异常。在这种情况下,如果异常是在其他地方创建的,您仍然想知道它是从 bar 抛出的,而不是在哪里创建的。我想正如 EJP 所说,您可以通过调用填充堆栈跟踪来选择这种行为,以便更多地解释为什么他们会以这种方式设计 throws 子句。
      • 我已经更新了答案。我不确定fillInStrackTrace() 会有你所说的行为。对于异常处理,您真的希望它尽可能明显。特别是对于其他查看您的代码的人。 IE。更喜欢在查看堆栈跟踪的 99% 的人所期望的同时创建和抛出异常。
      • 我刚刚对其进行了测试,fillInStackTrace() 确实按我的预期工作。值得注意的是,在您的示例中,堆栈跟踪显示异常从 bar 开始并在通往 main 的途中通过 foo,即使 foo 中没有额外的代码。问题不在于标准约定是什么,我知道我的方法似乎有点奇怪,但相信我在上下文中,这是有道理的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-24
      • 2010-09-28
      • 1970-01-01
      • 2017-08-18
      • 2014-12-10
      相关资源
      最近更新 更多