将泛型用于异常是明智的吗?

Fre*_*eit 12 java exception-handling

我的团队正在清理我们的使用,throws Exception并删除或替换它们,但有特殊例外.

常见的抛出是因为找不到实体.我们应该为每个实体类抛出泛型NotFoundException还是特定SomeClassNotFoundException的?

如果我们应该抛出一个特定的异常,我们应该为每个实体类型创建一个特定的Exception类吗?我们可以安全地使用仿制药吗?像这样class NotFoundException<T extends EntityBaseClass> extends Exception,然后构造函数负责声明我们正在处理的实体类型?

如果我们应该抛出一个特定的异常而不是使用泛型,那些异常是应该扩展还是实现NotFoundException抽象类或接口?

axt*_*avt 23

不允许将异常设为通用 - 它不会编译(JLS§8.1.2):

如果泛型类是Throwable的直接或间接子类,则是编译时错误

由于泛型的类型参数在运行时被擦除,因此无法区分子catch句中具有不同类型参数的泛型异常,因此不支持泛型异常.因此,您实际上没有选择使用通用异常.


NPE*_*NPE 11

这个问题的一个简单的试金石

我们应该为每个实体类型创建一个特定的Exception类吗?

在任何情况下我们都需要编写一个catch子句来捕获某个类X 而不是任何其他类抛出的"未找到"异常吗?

如果答案是肯定的,则需要另外一个ClassXNotFoundException; 否则,它可能不是.

至于问题的后半部分,该语言不允许对异常类型使用泛型.


Mik*_*uel 5

我们应该Exception为每个实体类型创建一个特定的类吗?

如果您的代码的调用者可以合理地从找不到实体定义中恢复,并且可以从每个实体类型采用不同的恢复策略中受益,那么是.否则没有.

我们可以安全地使用仿制药吗?像这个类一样,NotFoundException扩展了Exception,然后构造函数负责声明我们正在处理的实体类型?

它不会帮助您的代码的调用者切换与失败相关的实体类型.

即使您MyParameterizedException<T>因类型擦除而定义了异常类型,调用者也无法做到

 try {
   callYourCode();
 } catch (MyParameterizedException<TypeA> ex) {
   // some handling code
 } catch (MyParameterizedException<TypeB> ex) { 
   // some different handling code for type b
 }
Run Code Online (Sandbox Code Playgroud)

因为类型擦除它看起来像

 try {
   callYourCode();
 } catch (MyParameterizedException ex) {
   // some handling code
 } catch (MyParameterizedException ex) { 
   // some different handling code for type b
 }
Run Code Online (Sandbox Code Playgroud)

并且第二个catch块将是无法访问的代码,因此将在编译时被拒绝javac.将为类型b输入第一个catch块并键入实体(以及任何其他类型).

如果我们应该抛出一个特定的异常而不是使用泛型,那些异常是应该扩展还是实现NotFoundException抽象类或接口?

如果你的代码的调用者如果没有那么会感到惊讶然后是.

如果您的代码的调用者将受益于处理其他NotFoundExceptions 的代码处理实体失败,那么是.

如果您的代码的调用者可能不希望无法找到以与其他NotFound条件相同的方式处理的实体类型定义,则不会.


Mar*_*elo 5

而不是使用:

public Class EntityNotFoundException<T extends EntityBaseClass> extends Exception {

}
Run Code Online (Sandbox Code Playgroud)

你应该使用:

public Class EntityNotFoundException extends Exception {
    private Class<? extends EntityBaseClass> clazz;

    public EntityNotFoundException(Class<? extends EntityBaseClass> clazz) {
        this.clazz = clazz;
    }

    . . .
}
Run Code Online (Sandbox Code Playgroud)

这样,您可以保留对生成异常的实体类型的引用.要抛出其中一个例外,您可以使用:

throw new EntityNotFoundException(Customer.class);
Run Code Online (Sandbox Code Playgroud)

编译器验证Customer是否扩展了EntityBaseClass.