1

我有一个大型代码库,其中有很多很多实例

try {
   // attempt to do something important
} catch (Exception e) {
   // do something lame
}

反模式。大约 700 个实例。我想知道是否有一种工具(例如,IDE 或其他东西)可以神奇地大规模地用下一层专门的 catch 块替换所有这些东西。以如下所示的方式应用类似于 IntelliJ 或 Eclipse 的“使用 try/catch 包装”的大规模重构的东西。注意:我并不是说所有 700 都是已知IOException的;这只是一个示例,假设在特定情况下抛出的唯一异常类型是IOException)。

我正在寻求的重构是对try{}IntelliJ/Eclipse 所做的块进行相同语义分析的东西,以提供“用 catch 包装”或“添加到 throws 子句”快速修复:

try {
   // attempt to do something important
   // where an IOException is thrown
} catch (IOException e) {
   // still do something lame
}

我知道这并不能“解决”问题,但它节省了一步一步的手动考古工作。

想法?

有关检测一般异常捕获反模式的相关问题。

4

2 回答 2

2

我认为不存在任何工具来做你正在尝试的事情。我可以想到以下算法,但在脚本中自动化它可能需要一些时间……编写脚本所花费的时间甚至可能与手动进行更改所花费的时间一样多。

  1. 定义一个新的异常

class NeverThrown extends RuntimeException {}

  1. 全局替换catch (Exception e)catch (NeverThrown e)

  2. 编译所有文件

  3. 对于每次出现unreported exception .... must be caught...的异常,catch如果尚未添加,则将其添加到下一个块中,例如替换catch (NeverThrown e)catch (NeverThrown, IOException e)

  4. 删除所有出现NeverThrown,并删除类定义。

当然,更大的智力努力是确定要做什么而不是“一些蹩脚的事情”。您将无法批量进行,每个案例都必须单独检查。如果我是你,我会在第 3 步停下来,通过错误尝试找出如何处理报告的每个未捕获的异常。

或者您可以完全谴责已检查的异常并删除所有 try 和 catch 块,throws Exception在每个方法之后添加:)

于 2012-03-28T20:44:55.143 回答
2

鉴于问题是:

查找表格的所有块:

 try { ... }
 catch (Exception e) { ... }

 try { ... }
 catch ( T1 e ) { ... }
 ....
 catch ( Tn e ) { ... }

对于所有 T1,... Tn e,一个可以进行代码更改以及引发异常的原因的程序转换系统似乎是一个解决方案。

我们的DMS 软件再造工具包及其Java 前端可能会做到这一点。

您需要一个可以计算从主块内部抛出的异常集的分析器。您可能还想根据对象层次结构对这些异常进行分类;如果 Tm 是 Tn 的特化,您可能希望为 Tm 和 Tn 生成一个处理程序作为嵌套尝试。DMS 具有完整的类型分析,因此它可以确定代码中的类型,并由代码块抛出。必须编写自定义 DMS 代码来计算异常的对象层次结构。

您需要一个调用图,以便可以将调用图中发现的异常传播到尝试站点。我们有,但它需要为 Java 1.7 做一些工作。

您需要一个转换应用程序来修改代码。我认为您需要担心链式捕获来处理一般情况。使用 DMS,它应该如下所示:

rule specialize_catch(b_try: block,
      E: qualifed_identifer, e: IDENTIFIER, b_recover: block,
      c_pre: catches, c_post: catches):
   statement -> statement
 " try { \b_try } 
   \c_pre
   catch ( \E \e ) { \b_recover }
   \c_post "
 -> 
  " try { \b_try }
    \c_pre 
    catch ( \least_specialized\(\E\,\b_try\,\c_pre\) \e ) { \b_recover }
    catch ( \E e ) { \b_recover }
    \c_post "
    if exists_specialized_exception(E,b_try,c_pre);

要转换的语法是 *meta*quotes "..." 中的代码,以将其与重写规则的语法分开。重写规则有很多部分。它指定了一个名称(我们通常有数百个)。它提供了一组命名占位符(b_try、E、b_recover、...),表示目标语言(在本例中为 Java)中的特定命名句法形式,并以元引用之外的裸形式和转义(反斜杠)形式编写在元引号内。c_pre 是一系列 catch 结构的名称;我们可以这样做,因为“捕获”在摘要中形成了一个关联列表,对于 c_post 也是如此。它提供了可以调用自定义 DMS 机器来计算结果(布尔值或新语法 [树])的元函数调用(例如,least_specialized、exists_specialized_exception)。你' 请注意对 least_specialized 的元函数调用甚至对元函数调用的语法进行了转义(例如,逗号和括号),因为它们不是 Java 语言的一部分;在 Java 代码之外,这样的元函数调用不需要转义。最重要的是它有一个左侧(“匹配这个”,绑定元变量)和一个右侧(如果规则条件为真,则“用这个替换”。

元函数 least_specialized 和 exists_specialized 将计算主代码块 b_try 可能抛出的异常,以及由现有捕获 c_pre 处理的异常,以及当前异常类型 E、c_pre 之上和 E 之下最一般的异常,以及一个新的 catch块被插入。如果不存在,则 if 失败并且不再插入异常。您可能需要额外的转换来取消克隆重复的 b_recover 块。

我显然没有实现这一点,也可能没有完全考虑清楚。但我可以将此视为可能解决方案的途径。YMMV。

我会说对于 700 个实例,使用 DMS 执行此操作可能非常微不足道。如果您亲自花费 10 分钟(编辑、编译、哎呀……),那就是 7000 分钟或 ~ 100 小时,大约 2 周。我怀疑您是否可以将 DMS 配置为如此快速地执行此操作,尤其是以前从未这样做过。(我的公司有专业的 DMS 用户,这可能是一个可行的时间框架)。

但声称是一种工具可能确实存在。

于 2012-03-28T22:38:58.730 回答