-
我一直在搜索我们应该在什么时候创建自定义异常。我发现了这个例子:
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
的东西,那么我们的项目最终会出现许多自定义异常 -
我还发现了这个:
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
真的是一个好方法吗 -
我们什么时候不应该创建自定义异常?
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编码标准,抛出RuntimeException
、Exception
或Throwable
不是一个好的做法。因此,您永远不应该抛出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);
...
因此,当您不能重用内置异常时,您应该创建一个自定义异常。