来自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);
}
}
这些处理例外的方法是否存在差异或最佳做法?
答案 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)
}
}
}
因为接口声明了它可以返回的错误类型,所以该接口的客户端可以是一致且合理的。添加代码以处理FileNotFoundException
和SQLException
,然后实际的实现可能是,或者两者都不是很棒。
考虑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)
我会说NumberFormatException
和MyBusinessException
都很有用,但在不同的情况下。
它们通常出现在不同级别的类层次结构中:例如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
发生,则会吞下异常,因此用户永远不会看到发生了什么。如果您希望这种情况发生,那么这是您的最佳做法。
第二种情况很清楚。您捕获两个不同的异常并处理它们 (通过记录)一般来说这是一种更好的做法。
因此,两种不同情况的最佳做法取决于您想要达到的目标。关于美,这是完全主观的。