在catch块中编写业务逻辑

Jam*_*ann 5 java

我试图了解使用Java catch块的正确方法。我应该在那里写业务逻辑还是仅抑制错误?

我的问题在某种程度上与有关。请检查一下。

我的理解:

如果未检查到 异常,则最好的方法是用以下方式编写代码:

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

并避免这样的代码:

Integer n = null;
try {
    n = Integer.parseInt(reader.readLine());
}
catch(NumberFormatException ignored){
    n = 0;
}
Run Code Online (Sandbox Code Playgroud)

我的问题:

但是它将被检查的异常是什么,并且我在未找到搜索元素的情况下使用例如数据库异常抛出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...
Run Code Online (Sandbox Code Playgroud)

因此,我可以像上面列出的那样编写代码,还是应该使用与示例相同的模式?

zap*_*apl 2

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

但是,不要在还无法处理错误的地方捕获错误。您可能想知道较远的地方存在输入错误。

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

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

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

这是问题最多的版本。它表面上避免了 catch 块并添加了不需要的代码和代码分支。您应该使用第二个示例中的内容,因为它更干净 - 也就是说,如果您的业务逻辑实际上是将输入错误替换为 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();
}
Run Code Online (Sandbox Code Playgroud)

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

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

并以清晰的抽象方式处理案件。或者如果出现异常则返回,但如果一切正常则继续。但继续使用假物体通常是不对的。有可能。