为啥我们不能使用 RuntimeException 而不是创建自定义异常? [复制]

Posted

技术标签:

【中文标题】为啥我们不能使用 RuntimeException 而不是创建自定义异常? [复制]【英文标题】:Why can't we use RuntimeException instead of creating custom exceptions? [duplicate]为什么我们不能使用 RuntimeException 而不是创建自定义异常? [复制] 【发布时间】:2020-01-31 11:33:39 【问题描述】:

    我一直在寻找我们应该在什么时候创建自定义异常。我找到了这个例子:

     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("error occurred", e)? 我在互联网上看到很多创建类似自定义异常的示例,但我没有了解上述方法的真正好处是什么。

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

    我还发现了这个:

     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 真的是个好方法吗?

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

【问题讨论】:

谁说你不能?关键是:你不应该。如果你得到一个异常,你会更喜欢 LoggingFailedException 和 InvalidCertificateException,基本上已经告诉你出了什么问题,还是更喜欢深入调试所有东西,因为你抛出的所有东西都是相同的类型? Imo 如果你想捕捉那个异常,你应该创建一个自定义异常。否则内置异常应该没问题。 RuntimeException 及其子类是未经检查的异常。 - 我认为检查异常会更好 @Stultuske 如果你能用一些例子解释或提供更多解释,我会很高兴。您的意思是如果创建了自定义异常,我们可以通过查看我们的自定义异常名称轻松识别问题,这就是您的意思?顺便说一句,需要创建多少个自定义异常?我认为我们的项目最终会出现许多这样的自定义异常 如果异常是 LoggingFailedException 那么代码是自记录的 【参考方案1】:

要考虑的其他事情是为异常创建处理程序。

如果你抛出以下两个异常:new RuntimeException("User not found") 和 new RuntimeException("Event not created") 你如何处理它们?捕获每个运行时异常,然后让 if-else 比较消息?

从长远来看,这将是痛苦的。当您对引发异常的逻辑进行单元测试时也会发生同样的情况 - 您必须再次使用 if(ex.message.equals(someMessage)) 才能进行单元测试。

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

【讨论】:

【参考方案2】:
public class MyBusinessRuntimeException extends RuntimeException 
    // copy all the constructors you need

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

IncorrectFileExtensionException 不应直接扩展 Exception。它们处于完全不同的抽象级别。

考虑

 Exception
     FileException
         FileExtensionException
             IncorrectFileExtensionException
             UnsupportedFileExtensionException

【讨论】:

【参考方案3】:

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

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

【讨论】:

【参考方案4】:

根据SEI CERT Oracle Coding Standard for Java 抛出RuntimeExceptionExceptionThrowable 不是一个好习惯。因此,您永远不应该抛出 RuntimeException 而不是子类。

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

关于您的担忧:

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

您应该倾向于使用 Java 库中提供的Built-in 异常,这种方法将帮助您创建更少的自定义异常。根据 Joshua Bloch 在他的精彩著作 Effective Java 中:

重用标准异常有几个好处。其中最主要的是 它使您的 API 更易于学习和使用,因为它与 程序员已经熟悉的既定约定。一种 其次是使用你的 API 的程序更容易阅读 因为它们不会因为不熟悉的异常而杂乱无章。最后(和 最少),更少的异常类意味着更小的内存占用和 加载类所花费的时间更少。

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

例如,除了创建 IncorrectFileExtensionException 类之外,您还可以抛出带有精心编写的错误消息的 IllegalArgumentException

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

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

【讨论】:

以上是关于为啥我们不能使用 RuntimeException 而不是创建自定义异常? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥我在使用 RemoteFileTemplate 时会在日志中收到意外的 RuntimeException 警告?

为啥会发生此错误? java.lang.RuntimeException:ImageLoader 必须在使用前通过配置初始化

为啥捕获 RuntimeException 不被认为是一种好的编程习惯? [关闭]

RuntimeException : 宽度 (0) 和高度 (0) 不能 <= 0

Hive GenericUDF 错误 - RuntimeException typeInfo 不能为空

Apache Spark SQL 问题:java.lang.RuntimeException:[1.517] 失败:预期标识符