Try-catch:这是可接受的做法吗?

时间:2011-09-18 16:20:05

标签: java error-handling try-catch

我们已收到软件供应商提供的Java代码。它包含许多try-catch块,catch部分没有任何内容。他们到处都是。例如:

        try {
            spaceBlock.enable(LindsayModel);
        } catch (Exception e) {
        }

我的问题是:上述可接受的做法是否合适?如果是的话,何时?或者我应该继续删除所有这些“虚假”trycatch声明?

对我而言,这看起来像是一种糟糕的做法,但我在Java中没有足够的经验来确定。如果你不打算对它们做任何事情,为什么要抓错?在我看来,如果您确信异常绝对没有任何后果,并且您不关心是否发生异常,那么您只会这样做。但是,在我们的特定应用中并非如此。

编辑提供一些背景信息:我们从供应商那里购买了一个Java脚本产品。除产品外,他们还根据我们的需求提供了大量的概念验证脚本。这个脚本是“免费的”(虽然我们不会购买产品,如果它没有附带脚本),它“工作”。但是这个剧本真的很难建立起来,因为很多事情甚至我作为Java新手都认为是糟糕的做法,其中一个例子就是这种虚假的尝试捕捉业务。

8 个答案:

答案 0 :(得分:19)

这确实是一种可怕的做法。特别是捕捉Exception而非特定的东西会散发出难闻的气味 - 即使是NullPointerException也会被吞噬。即使确保特定抛出的异常没有真正的后果,也应该始终记录它:

try {
    // code
}
catch (MyInconsequentialException mie) {
   // tune level for this logger in logging config file if this is too spammy
   MY_LOGGER.warning("Caught an inconsequential exception.", mie);
}

然而,在这种情况下,异常不可能完全没有意义。我建议准确研究应用程序代码在这里想要接受的异常,以及它们对执行的真正含义。

一个重要的区别是try / catches是否用于吞下已检查的异常。如果是这种情况,它可能表示对程序员非常冷漠 - 有人只是想让他/她的代码编译。至少,代码应该修改:

try {
   // code
}
catch (SpecificCheckedException sce) {
   // make sure there is exception logging done farther up
   throw new RuntimeException(sce);
}

这将重新抛出未经检查的RuntimeException中包含的异常,从而有效地允许代码进行编译。即使这可以被认为是一个绑定但是 - 检查异常的最佳做法是在当前方法中单独处理它们,或者通过向方法签名添加throws SpecificCheckedException来进一步处理它们。

如上所述@Tom Hawtin,可以使用new Error(sce)代替new RuntimeException(sce),以避免任何额外的Exception捕获更远,这对于不是预计会被抛出。

如果没有使用try / catch来吞下已检查的异常,那么它同样危险,应该被删除。

答案 1 :(得分:8)

确实太糟糕了。吞下像这样的例外可能很危险。你怎么知道发生了什么坏事?

如果供应商写评论来记录并承认它(“我们知道我们在做什么”),我会感觉更好。如果在代码中有明显的策略来处理后果,我会感觉更好。将它包装在RuntimeException中并重新抛出;将返回值设置为适当的值。什么!

“到处都是”?是否有多个try / catch块乱丢代码?就个人而言,我不喜欢那个成语。我更喜欢每种方法一种。

也许你应该找一个新的供应商或自己编写。

答案 2 :(得分:2)

    try {
        meshContinuum.enable(MeshingModel);
    } catch (Exception e) {
    }

这看起来像未完成的代码。如果enable方法抛出异常,那么它将被代码捕获并吞没。如果没有,则尝试捕获非发生的异常是没有意义的。

检查方法以及throws exceptionName未遵循其签名的位置,然后从调用它们的位置删除空的try-catch语句。

理论上你可以把try-catch放在任何语句中。编译器不会抱怨它。但这没有意义,因为这样可以隐藏真正的异常。

您可以将此视为代码质量不佳的标志。您可能应该准备好遇到不同类型的问题。

答案 3 :(得分:1)

这不是最好的:

  • 它隐藏了异常的证据,因此调试更难

  • 可能会导致功能无声地失败

  • 这表明作者可能实际上想要处理异常,但从未接触过它

因此,可能存在这样的情况,例如实际上没有任何后果的异常(想到的情况是Python的mkdirs,如果目录已经存在则抛出异常),但通常,它不是那么好。

答案 4 :(得分:1)

不幸的是你不能只删除它,因为try块会抛出一个已检查的异常,然后它必须在方法的throws子句中声明。然后,该方法的调用者必须catch(但如果调用者也有catch (Exception e) {}憎恶,则不会这样做)。

作为替代方案,请考虑将其替换为

try {
    meshContinuum.enable(MeshingModel);
} catch (Exception e) {
    throw (e instanceof RuntimeException) ? (RuntimeException) e : new RuntimeException(e);
}

由于RuntimeException(以及扩展它的类)是未经检查的异常,因此不需要在throws子句中声明它们。

答案 5 :(得分:1)

您与供应商的合同有何规定?如果他们所写的内容,不良做法以及所有内容符合规范,那么他们会向您收取重写费用。

最好指定一组测试,这些测试将输入许多或所有这些try-catch块,从而失败。如果测试失败,你有一个更好的论据,让他们修复他们可怕的代码。

答案 6 :(得分:0)

面对它的可怕想法,完全取决于你实际上在呼唤什么。通常是出于懒惰或习惯性的不良行为。

答案 7 :(得分:0)

实际上...不是很快。

在某些情况下,可以忽略异常。

  • 假设已经发生了一个异常,并且我们已经在catch()中。在catch()中,我们希望尽最大努力进行清理(这也可能失败)。哪个异常返回?当然是原始的。代码如下:
    try {
        something-that-throws();
    } catch(Exception e) {
        try {
            something-else-that-throws();
        } catch(Exception e1) {}
        throw e;
    }
  • 当我们真的不在乎某个操作是否成功时,但是(不幸的是)如果失败发生,该操作的作者将引发异常。
    if (reinitialize) {
        try {
            FileUtils.forceDelete(sandboxFile); // delete directory if it's there
        } catch(Exception e) {}
    }

上面的代码保存了一个相当折磨的尝试,可以在删除沙箱文件之前查看它是否确实存在。