将未经检查的异常包装在已检查的异常中

3

将未经检查的异常包装为已检查的异常是否可行?

为什么会有这个问题?

我正在创建一个API,它将所有已检查的异常都封装在一个特定的API已检查的异常中。因此,我想知道未经检查的异常是否也可以包装在已检查的异常中。

对此有什么建议吗?如果它们可以被包装,那么请用一个可能有意义的情境来说明。


2
投下负评的人有意见吗? - Narendra Pathai
(我不是那个给你点踩的人,)我刚刚收到了一个“主要基于观点:许多好问题会根据专家经验产生一定程度的观点,但对于这个问题的回答往往几乎完全基于观点,而不是事实、参考资料或特定专业知识。”的标记,我认为这可能来自同一个人。 - Richard Tingle
是否可行取决于具体情况。 - Raedwald
4个回答

4

已检查异常应该用于调用者可以合理恢复的情况。通过抛出已检查异常,您强制调用者在catch子句中处理异常或向外传播异常。API用户可以通过捕获Exception并采取适当的恢复步骤来从异常条件中恢复。

例如,FileNotFoundException是一个已检查异常

try {
    FileInputStream fis = new FileInputStream(file);
    } catch (FileNotFoundException e) {
    // HANDLE THE EXCEPTION
}

即使找不到文件,如果用户采取了适当的恢复步骤(从不同位置读取文件等),应用程序仍然可以继续执行。
另一方面,应该使用“运行时异常”来表示无法进行恢复,并且继续执行会造成更多的伤害。很多时候,“运行时异常”用于指示前置条件违规:客户端违反了已定义使用您的API的合同。
例如,“ArrayIndexOutOfBoundsException”是一个“运行时异常”:
int[] aa = new int[2];
int ii = aa[2]; // java.lang.ArrayIndexOutOfBoundsException

由于访问数组元素的合同规定数组索引必须在0到数组长度减1之间,而我们违反了以上的先决条件。

再次假设您正在编写以下类

,其中areaCode不能为null。如果有人创建了一个没有areaCode
,将来在使用
时可能会造成更大的危害。在这种情况下,您可以使用IllegalArgumentException(运行时异常)来指示:

public class Address {
private String areaCode;

public Address(String areaCode) {
    if (areaCode == null) {
        throw new IllegalArgumentException("Area Code cannot be NULL");
    }
    this.areaCode = areaCode;
}
...
}

因此,建议在可能恢复的情况下使用已检查异常(checked exceptions),如果无法进行恢复或者存在任何前提条件违规,则应使用运行时异常(Runtime exception)

0
我正在创建一个API,将所有已检查的异常封装到特定的API已检查异常中。
为了实现这一点,如果您在catch(Exception e)之前没有明确使用catch(Runtime e),则无论如何都会包装未经检查的异常。除非有特定要求单独处理Runtime异常,否则通常会遵循这种做法。
对于服务来说,捕获运行时和已检查异常并将其转换为服务级别异常是可以接受的,以便调用者只需处理可能具有自定义属性、代码等的ServiceException
一个例子可能是拥有一个在IO API上工作的服务方法:
public void serviceA(String path) throws ServiceException {
try {
File f = new File(path); //Runtime - NPE etc
Reader r = .. //Checked IOException, may be some Runtime exception
}catch(Exception e) { //both runtime and checked
throw new ServiceException("CUSTOMMSG", e);
}
}

在这里,处理Runtime异常将是非常特定的情况,因为服务契约是通过ServiceException进行的,调用者了解并不知道如何处理Runtime异常。

为什么你要强制用户在任何情况下都捕获这个 ServiceException?如果用户不关心,给他忽略它的机会! - markusw
是的,对于某些服务可能是这样,但并非所有服务都是如此。例如,谷歌为各种服务公开了许多API,其中一些DFADFP会抛出带有详细代码、消息和建议的已检查异常,而其它一些服务则不会。我不知道是否存在一个通用规则。 - harsh

0

我没有点踩,但我总是对像“不要使用CheckedExceptions”这样的规则持谨慎态度。我对UncheckedExceptions的问题在于它使API用户更难以对异常做出反应,因为在大多数情况下,他们甚至不知道他们会遇到异常,直到代码运行并抛出异常。至少使用CheckedExceptions,API用户在编译时就知道他们必须处理的异常集合。我同意,定义不好的API会抛出很多已检查的异常,这可能很难使用,但我们应该鼓励开发人员设计更好的API,而不是隐藏其缺陷。 - DaveH
@DaveHowes 你也可以通过 throws 子句和 JavaDoc 声明你的方法会抛出未经检查的异常。对此没有问题。 - markusw
1
@MariuszS 给我一个例子,说明何时应该使用已检查异常。 - markusw
@markusw - “你也可以声明你的方法抛出未经检查的异常......”。我同意——但是谁会这样做呢?鉴于你所提到的文章大部分讨论开发人员如何糟糕地处理Checked异常,你认为这些相同的开发人员会在方法声明中放置Unchecked异常吗? - DaveH
我这么做是一个好的实践。当楼主想要构建API时,清晰的方法结构和文档非常重要! - markusw
显示剩余2条评论

0
@Narendra,你的API中的父类可以扩展Exception类,这样你的API就可以将已检查和未检查的异常包装在一起。或者你可以创建一个新的API,扩展RuntimeException以包括未经检查的异常。 对于我的实现,我更喜欢第一种选项,以便在需要重用超级引用时使用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接