【问题标题】:In Java catch block, how do you know which method/line throws the exception?在 Java 的 catch 块中,你怎么知道哪个方法/行抛出了异常?
【发布时间】:2016-01-16 00:04:33
【问题描述】:

在 try 块中,我想执行两个函数。如果第一个失败,则不要执行第二个。我还想打印出哪个功能失败了。

参见下面的代码。

try {
  a = func1();
  b = func2();  //won't execute if a failed
}
catch (Exception e) {
  //TODO: print a or b failed?
}

语言是否自然支持这种情况?

如果不是,以下是一种好的做法吗? (我想不出有什么问题。但这让我很担心,因为我不记得在catch 中看到有人使用return。)

try {
  a = func1();
}
catch {
  //print: a failed
  return; //if a failed then skip the execution of b
}

try {
  b = func2();
}
catch {
  //print: b failed
}

编辑: cmets总结:

  1. 从两种方法中抛出不同的异常。

    • 在这种情况下,方法是由其他人编写的,我无法控制。
  2. e.printStackTrace() 将打印行号和函数

    • 我想做的不仅仅是打印。更像是,如果失败,则执行以下代码。

【问题讨论】:

  • e.printStackTrace() 获取堆栈跟踪。或者从这两种方法中抛出不同的异常。
  • 这甚至无法编译。
  • 使用 slf4j 记录器记录您的代码。你会在 stacktrace 中看到类和方法被抛出异常。
  • 使用第二个变体,在catch 中没有return - 通常是个坏主意。或者,从您的方法中抛出不同的异常。
  • 堆栈跟踪已经有行号和失败的函数。你想做哪些它还没有做的事情?

标签: java exception try-catch


【解决方案1】:

你想要的是String methodName = e.getStackTrace()[0].getMethodName());

但这并不是一个好的做法。标准方法是使用日志框架中的适当方法记录异常,或者(如果编写控制台应用程序,Java 很少出现这种情况)将其打印到错误或标准输出,或者可选地打印到其他 PrintStream,例如使用printStackTrace(printStream)

但在大多数情况下,您希望将异常传播到上层并由适当的高级代码处理(或决定不处理)。捕获这样的异常会导致讨厌的错误。在 99% 的情况下,从 catch black 返回也是一个非常糟糕的主意,因为异常表示方法异常终止,而返回值则没有。

【讨论】:

    【解决方案2】:

    正如 dev-null 所写,e.getStackTrace() 可以提供帮助。但请注意,func1func2 本身可能不会引发异常,而是通过它们调用的其他方法引发异常。所以你需要遍历数组的所有元素,直到你点击func1func2

    在单独的 try 块中调用它们是绝对可行的,但它会变得很麻烦。

    【讨论】:

    • 所以你的意思是catch 中的return 不会受伤,对吧?
    • 伤害是什么意思?至少在你的例子中我没有看到问题。
    【解决方案3】:

    如果抛出异常,则记录堆栈跟踪将告知您是哪一行抛出了异常。如果 try/catch 中的第一行抛出异常,则不会执行下一行。

    【讨论】:

      【解决方案4】:

      这将起作用:

      String failedFunc = "func1";
      try {
          a = func1();
          failedFunc = "func2";
          b = func2();  //won't execute if func1() failed
      } catch (Exception e) {
          System.out.println("Func '" + failedFunc + "' failed: " + e);
      }
      

      当然,如果您所做的只是打印错误,那么打印堆栈跟踪将准确显示失败的位置。但是,如果您需要 failedFunc 的值而不需要完整的堆栈跟踪,则上面的代码很有用。

      【讨论】:

      • @BoristheSpider 也许,也许不是。如果您正在调用 10 个函数,并且想要一个只需要知道在失败之前它走了多远的错误处理程序,那么这可能会更好(不重复错误处理程序)。这完全取决于您为什么想知道,以及您打算对此做什么。
      • 在这个例子中,对于日志,我认为让日志框架处理它会更整洁。如果您想处理错误,那么让每个方法处理自己的错误可能会更好。我没有看到这个特定解决方案的作用。
      【解决方案5】:

      正如我在 cmets 中所说,您可以使用e.printStackTrace() 来确定@​​987654322@ 的原因。既然您表达了对不同行为的渴望,那么您有几个选择。你可以编写两个本地函数来装饰你的func1func2调用自定义Exceptions。类似的,

      class Func1Exception extends Exception {
          public Func1Exception(Exception e) {
              super(e);
          }
      }
      
      class Func2Exception extends Exception {
          public Func2Exception(Exception e) {
              super(e);
          }
      }
      

      然后你就可以写本地函数了

      private static Object func1Decorator() throws Func1Exception {
          try {
              return func1();
          } catch (Exception e) {
              throw new Func1Exception(e);
          }
      }
      
      private static Object func2Decorator() throws Func2Exception {
          try {
              return func2();
          } catch (Exception e) {
              throw new Func2Exception(e);
          }
      }
      

      然后你可以随心所欲地处理它们,

      try {
          a = func1Decorator();
          b = func2Decorator(); // this still won't execute if a failed
      } catch (Func1Exception e) {
          // a failed.
      } catch (Func2Exception e) {
          // b failed.
      }
      

      如果您希望func2 即使在失败时也能运行,您可以使用finally 块,

      try {
          a = func1Decorator();
      } catch (Func1Exception e) {
          // a failed.
      } finally {
          try {
              b = func2Decorator(); // this will execute if a fails
          } catch (Func2Exception e) {
              // b failed.
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2013-03-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多