【问题标题】:Wrapping unchecked exception in a checked exception将未经检查的异常包装在已检查的异常中
【发布时间】:2013-11-26 11:04:57
【问题描述】:

将 Unchecked 异常包装到 Checked 异常中作为一种做法是否可取?

为什么要问这个问题?

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

对此有什么建议吗?如果可以将它们包装起来,那么如果用有意义的情况进行说明,那就太好了。

【问题讨论】:

  • 反对者是否愿意发表评论?
  • (我不是反对者,但)我刚刚得到一个“主要基于意见:许多好的问题会根据专家经验产生一定程度的意见,但这个问题的答案往往是完全基于意见,而不是事实、参考资料或特定专业知识。”我假设来自同一个人的标志
  • 是否可取取决于具体情况。

标签: java exception-handling


【解决方案1】:

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

例如,FileNotFoundExceptionchecked exception

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

即使找不到文件,如果用户有适当的恢复步骤(从不同位置读取文件等),应用程序也可以继续执行。

另一方面,Runtime exceptions 应该用于表示无法恢复并且继续执行会造成更大的伤害。很多时候,runtime exceptions 用于指示违反前提条件:已定义为使用您的 API 的合约被您的 API 的客户端违反。

例如,ArrayIndexOutOfBoundsExceptionruntime exception

int[] aa = new int[2];
int ii = aa[2]; // java.lang.ArrayIndexOutOfBoundsException

因为访问数组元素的约定规定数组索引必须在零和数组长度减一之间,而我们违反了上面的前提条件。

再次,假设您正在编写一个类Address,如下所示,其中areaCode 不能是null。如果有人在没有areaCode 的情况下创建了Address,那么将来使用Address 时可能会造成更大的伤害。在这里,您可以使用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

【讨论】:

    【解决方案2】:

    我正在创建一个 API,它将所有检查的异常包装到一个 API 特定的检查异常。

    为了实现这一点,如果你没有在catch(Exception e) 之前明确地拥有catch(Runtime e),那么无论如何你也要包装未经检查的异常。除非有特殊要求单独处理 Runtime 异常,否则通常遵循哪个 IMO。

    服务可以同时捕获服务级别异常的运行时异常和检查异常,这样调用者将只处理可能具有自定义属性、代码等的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?如果用户不关心,就给他机会忽略它!
    • 是的,某些服务可能是这种情况,但某些服务可能并非如此。例如,google 为各种服务公开了许多 API,一些 DFADFP 抛出带有详细代码的检查异常,msg 建议,而它的一些服务没有……我不知道黄金法则……
    【解决方案3】:

    一个建议:不要使用 CheckedExceptions!始终尝试让您自己的 Exception 从 RuntimeException 继承,以让您的 API 用户选择是否喜欢对异常做出反应!

    这是描述该问题的博文:http://jandiandme.blogspot.de/2013/05/why-javas-checked-exceptions-are-issue.html

    编辑:请您评论您的否决票!

    【讨论】:

    • 我没有投反对票,但我总是对诸如“不要使用 CheckedExceptions”之类的规则保持警惕。我对 UncheckedExceptions 的问题是它使 API 用户更难对异常做出反应,因为在大多数情况下,他们甚至不知道在代码运行并抛出异常之前他们会遇到它。至少对于 CheckedExceptions,API 用户知道他们必须在编译时处理的一组异常。我同意抛出大量检查异常的定义不明确的 API 使用起来会很痛苦,但我们应该鼓励开发人员设计更好的 API,而不是隐藏其缺陷
    • 不要使用 CheckedExceptions! - 这取决于,最好说 不喜欢使用 CheckedExceptions! :) (我也没有投反对票)
    • @DaveHowes 您还可以通过throws 子句和JavaDoc 声明您的方法抛出未经检查的异常。看到没有问题。
    • @MariuszS 举一个例子,什么时候应该使用检查异常。
    • @markusw -“你可以还声明你的方法抛出未经检查的......”。我同意 - 但谁这样做?鉴于您参考的很多文章都在谈论开发人员处理 CheckedExceptions 很糟糕,是什么让您认为这些开发人员会将 UncheckedExceptions 放入方法声明中?
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2010-10-03
      • 1970-01-01
      • 1970-01-01
      • 2015-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多