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)我们什么时候不应该创建自定义例外?
答案 0 :(得分:5)
public class MyBusinessRuntimeException extends RuntimeException {
// copy all the constructors you need
}
这是一个好习惯,因为它有助于对错误类型进行分组和区分。您可以声明“我的API抛出MyBusinessRuntimeException
类型”,并抽象出您无法控制的其他RuntimeException
类型。它会告诉用户他们将要使用的异常,以及应该将哪些异常视为异常。
IncorrectFileExtensionException
不应直接扩展Exception
。它们处于完全不同的抽象级别。
考虑
Exception
FileException
FileExtensionException
IncorrectFileExtensionException
UnsupportedFileExtensionException
答案 1 :(得分:4)
首选自定义例外的原因是因为它们可以告诉您确切的问题。将所有内容都作为运行时异常减少了抛出异常的麻烦,是的,但是如果您有多个连续运行的代码片段,每个代码片段都可能以自己的方式出错,那该怎么办?在某些情况下,您希望使用不同的逻辑分别处理这些异常。
这也允许将来进行更好的测试。例如,如果您想测试代码是否正常运行,则还想测试程序是否抛出正确的异常。通过使用单独的类,您可以快速检测是否执行了导致抛出该特定异常的正确逻辑。
答案 2 :(得分:4)
要考虑的另一件事是为异常创建处理程序。
如果抛出以下两个异常:new RuntimeException(“找不到用户”)和new RuntimeException(“未创建事件”),您将如何处理它们?捕获每个运行时异常,然后使用if-else比较消息?
从长远来看,那将是痛苦的。当您引发异常的单元测试逻辑时,也会发生同样的情况-您必须再次使用if(ex.message.equals(someMessage))进行单元测试。
然后,当不同业务逻辑的异常消息相同时会发生什么?只需使用自定义异常进行操作,就可以轻松处理流程-从使捕获层次结构清晰到创建一些自定义解决方案来告诉处理程序如何行为(例如,告诉控制器建议抛出404)
答案 3 :(得分:4)
根据SEI CERT Oracle Coding Standard for Java掷RuntimeException
,Exception
或Throwable
来说不是一个好习惯。因此,您永远不应抛出RuntimeException
而不是子类。
方法不得抛出RuntimeException,Exception或Throwable。 处理这些异常需要捕获RuntimeException,这是 ERR08-J不允许。不要捕获NullPointerException或任何 它的祖先。此外,抛出RuntimeException可能导致 细微的错误;例如,呼叫者无法检查 确定为什么抛出它,因此无法尝试恢复。 方法可以抛出从Exception子类继承的特定异常 RuntimeException。请注意,构造一个 专门用于单个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);
...
因此,当您不能重用内置的异常时,应该创建一个自定义异常。