检测Java异常的负责变量

时间:2014-07-11 16:08:47

标签: java exception exception-handling fault

我有一组Java程序正在获得一些运行时异常。我想知道是否有一个自动机制来识别导致异常的罪魁祸首变量。

例如:

public int multiply(String x, String y){
    return Integer.parseInt(x) * Integer.parseInt(y);
}

当你致电multiply("4","ab")时,那么在运行时,我们会得到一个NumberFormatException。是否有任何自动化流程来识别变量y是否导致/导致此异常?

EDIT1:

在收到精彩开发人员的一些建议之后,我认为它无法在代码级别解决,而是我应该在Java编译器中做一些事情。有没有人想过更改可能有助于这种情况的Java编译器?

即使在编译器中不可能,任何人都可以提出有关JVM中的更改的建议吗?

3 个答案:

答案 0 :(得分:2)

更新

  

我认为它无法在代码级别解决,而是我应该在Java编译器中做一些事情。

根据定义,编译器无法检测到RuntimeException,只能在程序执行时捕获和处理它们。这可以在代码级别"解决

;

  

即使在编译器中不可能,任何人都可以提出有关JVM中的更改的建议吗?

尽管我尽了最大的努力,你仍坚持沿着这条道路前进,所以我将尝试解释你将要做的事情。但是要明白a)这是非常复杂的,并且b)几乎肯定不是正确的解决方案。 修复您的代码,而不是JVM

您基本上需要重新设计Java bytecode以包含所需的其他上下文,并更改compile the JDK from source。这在理论上是可行的,因为Java是开源的,但它将是一项英勇的事业。没有"给我更多信息"标志你可以开箱即用JVM;这是JVM Options的列表。


真正的答案从这里开始:

这取决于你的意思"自动化"。据我所知,没有办法检查异常以确定哪个变量导致错误(我希望它对NPE来说是真的,会非常有帮助)。但是您可以改进代码以使其更加清晰。

使用调试程序逐步执行程序

在我们进入自动化之前,一个选项是use the Java debugger逐行逐步执行代码并确切地查看故障发生的位置。这是一个高度手动的过程,但可以帮助您难以理解故障。

将特殊电话拆分为单独的行

堆栈跟踪确实提供了相关的行号,因此如果您将方法更改为:

public int multiply(String x, String y){
  int intX = Integer.parseInt(x);
  int intY = Integer.parseInt(y);
  return intX * intY;
}

然后NumberFormatException现在将出现在此函数的第一行或第二行,让您看到导致错误的行。

使用更多上下文提升包装器异常

行号并不是最有用的信息,我们可以通过提高自己的例外来做得更好:

private int parseIntMsg(String num, String desc)
      throws IllegalArgumentException {
  try {
    return Integer.parseInt(num);
  } catch (NumberFormatException e) {
    throw new IllegalArgumentException(
        "Failed to parse "+desc+"; was '"+num+"'", e);
  }
}

public int multiply(String x, String y) {
  return parseIntMsg(x, "x") * parseIntMsg(y, "y");
}

现在,这会使IllegalArgumentException消息更加清晰Failed to parse x; was 'ab'

在调用此方法之前进行完整性检查

这里真正发生的事情是你没有在合适的时间处理这个错误案例。相反,尽早进行理智检查,并明确处理它们。您是否正在从用户读取字符串?明确检查一下号码,然后将其交还给用户,如果不是,请更正,而不是等到你的代码的肚子里然后绕过可能会或可能不会的字符串。是有效的整数。实际上,您应该对您已定义的multiply(String, String)方法毫无用处。相反,将输入显式解析为您要使用的类型,然后在验证解析成功后显式处理它们。有关此主题的更多想法,请参阅Why is it good to split a program into multiple classes?


还要考虑使用优秀的Guava库中的Preconditions;这些实用程序方法允许您添加大量丰富的错误消息,并期望您的代码失败时会发生什么。

答案 1 :(得分:0)

我认为你需要一些可以在异常后打印输入参数的拦截器。例如,您可以在这种情况下使用AspectJ。以下是如何执行此操作的示例AspectJ-catch-handle-exception

答案 2 :(得分:0)

对于您的示例,您可以做的是:

public int multiply(String x, String y){
    if (!x.matches("(\d+|\d*\.\d+)")) {
        // give out that x is not a number
    } else if (!y..matches("(\d+|\d*\.\d+)")) {
        // give out thaqt y is not a number
    } else {
        return Integer.parseInt(x) * Integer.parseInt(y);
    }
}

与异常相关的最好的事情是控制它们何时发生。即使您使用的函数抛出异常,也要确保是您的代码决定是否报告此异常。

可能存在异常可接受的情况,您可以在日志中提及它并让代码继续,或者您停止流程并提及您为什么这样做,以免导致对可怜的毫无疑问的用户造成混淆。