为什么我们不能使用 RuntimeException 而不是创建自定义异常?


  1. 我一直在搜索我们应该在什么时候创建自定义异常。我发现了这个例子:

    public class IncorrectFileExtensionException extends Exception {
    public IncorrectFileExtensionException () {
    }
    public IncorrectFileExtensionException (String message) {
    super (message);
    }
    public IncorrectFileExtensionException (Throwable cause) {
    super (cause);
    }
    public IncorrectFileExtensionException (String message, Throwable cause) {
    super (message, cause);
    }
    }
    

    提供上述自定义异常的真正价值是什么与其创建上面的自定义异常,为什么我不能抛出一个新的RuntimeException("发生错误",e)我在互联网上看到了很多创建类似自定义异常的例子,但我不明白上述方法的真正好处是什么。

    如果我们创建类似IncorrectFileExtensionException的东西,那么我们的项目最终会出现许多自定义异常

  2. 我还发现了这个:

    public class MyUncheckedBusinessException extends RuntimeException {
    private static final long serialVersionUID = -8460356990632230194L;
    private final ErrorCode code;
    public MyUncheckedBusinessException(ErrorCode code) {
    super();
    this.code = code;
    }
    public MyUncheckedBusinessException(String message, Throwable cause, ErrorCode code) {
    super(message, cause);
    this.code = code;
    }
    public MyUncheckedBusinessException(String message, ErrorCode code) {
    super(message);
    this.code = code;
    }
    public MyUncheckedBusinessException(Throwable cause, ErrorCode code) {
    super(cause);
    this.code = code;
    }
    public ErrorCode getCode() {
    return this.code;
    }
    }
    

    这在某种程度上比IncorrectFileExtensionException要好,因为我们至少提供了一些错误代码。但是,如果所有自定义异常都像上面那样结束(我的意思是带有错误代码),该怎么办?

    我的问题是:自定义异常的最佳实践是什么?我们应该在什么时候进行自定义例外处理?IncorrectFileExtensionException真的是一个好方法吗

  3. 我们什么时候不应该创建自定义异常?

public class MyBusinessRuntimeException extends RuntimeException {
// copy all the constructors you need
}

这是一个很好的做法,因为它有助于对错误类型进行分组和区分。您可以声明"我的API抛出MyBusinessRuntimeException类型",并抽象出您无法控制的其他RuntimeException类型。它会告诉用户他们要处理什么异常,以及他们应该将哪些异常视为异常。

CCD_ 6不应该直接扩展CCD_ 7。它们处于完全不同的抽象层次。

考虑

Exception
FileException
FileExtensionException
IncorrectFileExtensionException
UnsupportedFileExtensionException

需要考虑的另一件事是为异常创建处理程序。

如果抛出以下两个异常:新的RuntimeException("找不到用户")和新的RuntimeException("未创建事件"),如何处理它们?捕获每个运行时异常,然后使用if-else来比较消息?

从长远来看,这将是令人头疼的事。当您的单元测试逻辑抛出异常时也会发生同样的情况——您必须再次使用if(e.message.equals(someMessage))才能进行单元测试。

然后,当不同业务逻辑的异常消息相同时,会发生什么?只需使用自定义异常操作,就可以轻松处理流-从明确捕获层次结构到创建一些自定义解决方案,告诉处理程序如何操作(例如告诉控制器建议抛出404)

首选自定义异常的原因是因为它们可以准确地告诉您问题所在。将所有内容都作为运行时异常可以减少抛出异常的麻烦,是的,但如果您有多段代码连续运行,每段代码都可能以各自的方式出错,该怎么办?在某些情况下,您希望使用不同的逻辑分别处理这些异常中的每一个。

这也允许在未来进行更好的测试。例如,如果你想测试你的代码是否正常运行,你也应该测试你的程序是否抛出了正确的异常。通过使用单独的类,您可以快速检测是否执行了导致抛出特定异常的正确逻辑。

根据SEI CERT针对Java的Oracle编码标准,抛出RuntimeExceptionExceptionThrowable不是一个好的做法。因此,您永远不应该抛出RuntimeException而不是子类。

方法不得引发RuntimeException、Exception或Throwable。处理这些异常需要捕获RuntimeExceptionERR08-J不允许。不要捕获NullPointerException或任何它的祖先。此外,抛出RuntimeException可能导致细微错误;例如,调用程序无法检查的异常确定它被抛出的原因,因此无法尝试恢复。方法可以抛出从exception或运行时异常。请注意,允许构建专门用于单抛出语句的异常类。

关于您的担忧:

如果我们创建了像IncorrectFileExtensionException这样的异常,那么在我们的项目中最后出现了许多自定义异常。

您应该喜欢使用Java库中提供的内置异常,这种方法将帮助您创建更少的自定义异常。根据Joshua Bloch在他的精彩著作《高效Java》中的说法:

重用标准异常有几个好处。其中最主要的是它使API更易于学习和使用,因为它与程序员已经熟悉的既定惯例。A.其次是使用API的程序更容易阅读因为它们不会被不熟悉的例外情况弄得一团糟。最后(和最少),更少的异常类意味着更小的内存占用空间加载类所花费的时间更少。

最常见的重用异常类型是IllegalArgumentException

例如,您可以抛出一个IllegalArgumentException,其中包含一条写得很好的错误消息,而不是创建IncorrectFileExtensionException类。

...
String message = String.format("'%s' is an incorrect file extension.", fileExtension);
throw new IllegalArgumentException(message);
...

因此,当您不能重用内置异常时,您应该创建一个自定义异常。

最新更新