Java异常包装:糟糕的做法?

时间:2017-11-16 08:51:02

标签: java exception exception-handling software-quality

来自PHP世界,只有一种方法可以编写异常处理..我发现Java中的异常包装有点"丑陋":

public void exampleOneException(String input) throws MyBusinessException {
    try {
        // do something
    } catch (NumberFormatException e) {
        throw new MyBusinessException("Error...", e);
    }
}

我更喜欢使用这种风格:

public void exampleTwoException() {
    try {
        // do something
    } catch (MyBusinessException e) {
        log.error("Error...: " + e);
    } catch (NumberFormatException e) {
        log.error("Error...: " + e);
    }
}

这些处理例外的方法是否存在差异或最佳做法?

4 个答案:

答案 0 :(得分:6)

这些都是针对两种不同场景的有效方法。

在第一种情况下,该方法无法对异常做任何明智的事情,但它必须"报告"它向上。这样调用者就可以捕获异常并决定如何处理异常(例如取消流程,向用户弹出消息,记录消息等)。

在第二种情况下,您捕获异常并将其记录下来,从而有效地将调用程序中的故障隐藏起来。如果调用者并不真正关心操作是否成功,则此类处理可能很有用。

答案 1 :(得分:3)

第一个例子通常被视为更好的方法。

您也不应该认为MyBusinessException 包装 NumberFormatException,而NumberFormatException原因 MyBusinessException

异常应该适合于公开的接口。接口的调用者不应该知道或处理实现细节。除非NumberFormatException在调用exampleOneException时作为一种错误真正有意义,否则应将其转换为更合适的例外。

更具体的示例通常包括不同的实现,其中不应要求接口的用户处理实现细节(在编译时甚至可能不知道)。

interface MyRepository {
    Object read(int id) throws ObjectNotFoundException;
}

// a sql backed repository
class JdbcRepository implements MyRepository {
    public Object read(int id) throws ObjectNotFoundException {
        try { ... }
        catch (SQLException ex) {
            throw new ObjectNotFoundException(ex);
        }
    }
 }

// a file backed repository
class FileRepository implements MyRepository {
    public Object read(int id) throws ObjectNotFoundException {
        try { ... }
        catch (FileNotFoundException ex) {
            throw new ObjectNotFoundException(ex)
        }
    }
}

因为接口声明了它可以返回的错误类型,所以该接口的客户端可以是一致且合理的。添加代码以处理FileNotFoundExceptionSQLException,然后实际的实现可能是,或者两者都不是很棒。

考虑FileRepository的实施中是否有多个地方可以抛出FileNotFoundException。这是否意味着每个人都暗示找不到对象

在考虑选项二exampleTwoException时,重要的是要意识到您的catch块有效地表明已经减轻了发生的任何错误的影响。 的情况,其中合理地忽略了已检查的异常,但它更可能是一个简单的

try { ... }
catch (SomeException ex) {
    log.error("caught some exception", ex);
}

实际上是开发人员没有考虑异常后果的结果,或者代码应该包含FIXME

当您看到catch (Exception ex)或不合情理的catch (Throwable ex)时更是如此。

最后,您是否希望成为挖掘应用程序的人,找到您需要添加(还)另一个catch块以处理新实现的所有位置?也许这是catch (Exception ex) ...

的原因

始终抛出适合抽象的异常

答案 2 :(得分:1)

我会说NumberFormatExceptionMyBusinessException都很有用,但在不同的情况下。

它们通常出现在不同级别的类层次结构中:例如NumberFormatException是较低级别的异常,如果用户没有,则可能不希望在更高级别(例如用户界面)公开它从中恢复的力量。在这种情况下,抛出MyBusinessException并显示一条信息性消息更为优雅,例如说明上一步中的某些内容供应不当或发生了一些内部处理错误,他/她需要重新启动该过程。 / p>

另一方面,如果你的函数在中级使用(例如API)并且开发人员有办法从异常行为中恢复,NumberFormatException更有用,因为它可以处理以编程方式,应用程序的流程可以以最小的中断继续(例如,提供默认的有效数字)。或者,这可以指示代码中应该修复的缺陷/错误。

有关如何遵循使用例外的最佳做法的详细信息,请阅读Effective Java by Joshua Bloch中的Item 61 - Throw exceptions appropriate to the abstraction

答案 3 :(得分:0)

从简洁明了的代码来看,你并没有朝着正确的方向前进 首先,您不需要对方法标头已经抛出的Exception使用try / catch。因此,在您的第一种情况下,代码应如下所示:

 public void exampleOneException(String input) throws MyBusinessException {
    // do something
 }

这更漂亮了吗? 在上面的情况下,如果MyBusinessException发生,则会吞下异常,因此用户永远不会看到发生了什么。如果您希望这种情况发生,那么这是您的最佳做法。

第二种情况很清楚。您捕获两个不同的异常并处理它们 (通过记录)一般来说这是一种更好的做法。

因此,两种不同情况的最佳做法取决于您想要达到的目标。关于美,这是完全主观的。