在catch块

时间:2015-11-30 08:03:43

标签: java

我正在尝试理解使用java catch块的正确方法。我应该在那里编写业务逻辑还是只是抑制错误?

我的问题在某些方面与this one有关。请检查一下。

我的理解:

如果未选中异常,最好的方法是以下一种方式编写代码:

Integer n = null;
try {
    n = Integer.parseInt(reader.readLine());
}
catch(NumberFormatException e){
    log.error('Can't parse string');
}
if (n == null) {
    n = 0;
}

并避免像这样的代码:

Integer n = null;
try {
    n = Integer.parseInt(reader.readLine());
}
catch(NumberFormatException ignored){
    n = 0;
}

我的问题:

但它会被检查例外,我会工作,例如使用数据库时,如果找不到搜索元素,则会抛出异常NoSuchElement:

User user = null;

try {
    user = User.findById(userId);
} catch (NoSuchCategoryException e) {
    log.error('User {} doesn't exist.', userId);
    user = new User();
}
user.setUsername('someName');
etc...

那么我可以编写上面列出的代码,还是应该使用与我的第一个代码相同的模式?

2 个答案:

答案 0 :(得分:2)

Catch块是常规控制流,没有必要避免它们。

但是,请勿在无法处理错误的地方捕获错误。您可能想知道更远的地方有输入错误。

通过将结果替换为null手动发出错误信号非常容易出错(NullPointerException万岁)并且您很容易失去null的含义。手动添加所有控制流以在短路径上将这样的替换值传播回调用者也并不总是很好,因为如果您使用该异常,您将免费获得所有这些。经验法则是:更少的代码更清晰。

异常的黄金法则是"catch late"(或者更常见的“处理迟到”):在包含知道该做什么的业务逻辑的地方。在某些情况下,这意味着用未经检查的异常替换已检查的异常,以便它可以通过不允许添加throws子句的预定义接口传播。

Integer n = null;
try {
    n = Integer.parseInt(reader.readLine());
}
catch(NumberFormatException e){
    log.error('Can't parse string');
}
if (n == null) {
    n = 0;
}

这是最有问题的版本。它表面上避免了阻塞并添加了不需要的代码和代码分支。您应该使用第二个示例中的内容,因为它更清晰 - 也就是说,如果您的业务逻辑实际上是用0替换输入错误,则默认忽略它们。大部分时间都没有。立即返回控制&信息通常发回给来电者的信息。

这里没有抓到可能是对的(呃)。或者使用常规API或不同的异常来捕获和替换异常。什么适合你取决于。

另一个问题告诉您的是不要在您自己的API中过度使用异常。您可以找到一个干净的API /抽象,在不使用异常的情况下发出错误信号。当抛出异常的地方和需要处理异常的地方在概念上远离(架构层等)时,不使用异常特别有用。在这些情况下,API的异常并不是很好,因为它会导致每个人必须拥有的一堆throws子句(这是对细节https://en.wikipedia.org/wiki/Dependency_inversion_principle添加依赖关系)或需要了解其他实现细节的代码代码,即在其他地方抛出未经检查的异常。

但如果你在合理的范围内包含例外,那么它们绝对可以使用并且可以让生活更轻松。使用普通旧java的所有功能并不违反规则。

User user = null;
try {
    user = User.findById(userId);
} catch (NoSuchCategoryException e) {
    log.error('User {} doesn't exist.', userId);
    user = new User();
}

看起来像一个典型的情况,你不应该像这样处理错误。 “假”数据库对象很容易导致假定存在正确输入的代码。假设是这种情况,你想避免例外,你可以粗略地做

try {
    return Optional.of(User.findById(userId));
} catch (NoSuchCategoryException e) {
    log.error('User {} doesn't exist.', userId);
    return Optional.empty();
}

并使用干净的抽象处理案例。或者您在异常的情况下返回,但如果一切正常,请继续。但继续使用假物体往往是不对的。它可以。

答案 1 :(得分:0)

您可以在任何catch块上使用您想要的任何代码。例如,我通常使用它们来断开循环或在用户界面上显示特殊事件。