【问题标题】:Checker for "unused catch clause variable"? [closed]检查“未使用的 catch 子句变量”? [关闭]
【发布时间】:2021-07-24 15:04:30
【问题描述】:

TL;dr 版本:(Java)如何检查 catch 子句中未使用的异常变量以避免无意中吞下错误。也许使用 checkstyle 之类的工具(通过 Maven 构建时插件)或使用代码模式。

您经常在代码中编写一个 try/catch 块,您可以在其中捕获内部异常,将其包装在更有意义的异常(链式异常)中,然后向上抛出调用堆栈。

有时,人们往往会忘记链接异常(拼写错误)并在没有根本原因的情况下抛出包装异常。错过这一点显然会导致调试噩梦。有没有办法通过构建时插件(用于 Maven)来检测和警告/错误此类实例?

有效:

try {
    ...
} catch (IOException e)  {
    throw new MyException("API failure", e);
}

无效:

try {
    ...
} catch (IOException e) {
    throw new MyException ("API Failure");
}

此外,如果它打算忽略异常,检查器应该能够允许注释以禁用该行的规则,或者可能将变量命名为catch (IOException ignored)

我知道 checkstyle 有一个空 catch 块的检查器,但上面的场景要广泛得多。未使用的局部变量似乎也无法解决。

是否有可用的检查工具来避免这种常见错误?

一个愚蠢的解决方案可能是让 MyException 的所有构造函数都将 Exception 作为参数(当不需要链接时,显式传递 null )。这感觉不是解决此问题的最佳方法,因此寻找某种检查器...

【问题讨论】:

  • 致接近者:为极其具体的用例寻求“推荐”并不是那个“接近”选项的意图。考虑一个问题'我如何启用此检查;如果有帮助,请随意回答您熟悉的任何工具。
  • 感谢@rzwitserloot,我添加了“how to”变体作为 tldr,以使具体性更清晰......
  • @rzwitserloot “这不是'关闭'选项的意图”你能指出支持它的文档吗?在近距离投票文本中没有具体说明。
  • 我会用 Google 的 Error Prone 来做到这一点。其他工具可用,但这是我最熟悉的。
  • 好吧,至少,如果源代码有一个带有ignored 变量的catch 和一个SuppressWarnings 注释,作为开发人员,我会理解发生了什么;换句话说,我的意图很清楚。

标签: java lint checkstyle


【解决方案1】:

我不太确定“使用变量”是否是您想要启用的检查。在您实际上(喘气!)有能力正确处理情况的几个捕获块中(与重新抛出它或那个旧栗子,“记录并继续前进”的愚蠢相比),那么通常您需要知道的就是它被抛出。命名异常变量 ignored 只是为了确保 linter 工具不会抱怨它然后导致 更糟糕 代码,因为 ignored 作为变量名通常被理解为意味着 整个抛出的异常将被忽略,而不仅仅是 throwable 的内容。

当然,您可以发明一个新术语来表示“异常不会被忽略,但可抛出对象传达的所有信息都是”。

说明:

  public Config getUserConfig() {
      try {
        return Config.parse(Files.readString(Paths.get("myapp.conf")));
      } catch (NoSuchFileException e) {
        return Config.defaultConfig();
      }
  }
}

对我来说似乎很好;要么将 e 重命名为 ignored,要么将 @SuppressWarnings 推到那里,这显然是次优的。

也许规则可以调整为:

  1. 如果 catch 正文完全为空,则需要注释或可抛出的 varname 需要为 ignored
  2. 任何 catch 主体中的任何和所有 throw new 语句(如 throw 语句,其参数是 new X() 表达式)必须将可抛出的 varname 作为第一个或第二个参数,或 em> 构造函数必须是 AST-wise 封装方法调用的接收者,即initCause。那是因为并非所有异常类型都有带原因的构造函数(我认为,原因作为一个概念直到 java 1.4 左右才存在?所以,遗留原因)。

换句话说:

throw new Foo(whatever, e); // okay
throw new Foo(whatever).initCause(e); // okay
throw new Foo(whatever); // not okay

说了这么多,不,我不知道有任何 linting 工具可以做任何事情。它必须是源代码级的,编写插件应该不难;大多数 linter 工具可以轻松添加您自己的规则。任何基于 LST 的分析器(在源上运行,但不是作为原始字符袋,而是作为已经完全归因和链接起来的抽象语法树,将其变成逻辑语法树的分析器)应该使它变得容易。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-28
    • 1970-01-01
    • 2018-02-16
    • 2011-10-05
    • 1970-01-01
    • 2016-03-15
    • 2021-09-11
    相关资源
    最近更新 更多