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

时间:2011-07-25 15:12:55

标签: java exception-handling

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

常见的抛出是因为找不到实体。我们应该为每个实体类抛出通用的NotFoundException还是特定的SomeClassNotFoundException

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

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

5 个答案:

答案 0 :(得分:23)

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

  

如果泛型类是Throwable

的直接或间接子类,则是编译时错误

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

答案 1 :(得分:11)

对问题的简单试金石

  

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

  

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

如果答案为“是”,则需要单独的ClassXNotFoundException;否则,它可能不是。

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

答案 2 :(得分: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
 }

因为类型擦除它看起来像

 try {
   callYourCode();
 } catch (MyParameterizedException ex) {
   // some handling code
 } catch (MyParameterizedException ex) { 
   // some different handling code for type b
 }

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

  

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

如果你的代码的调用者没有那么会感到惊讶,那么就是。

如果代码的调用者可以从处理其他NotFoundException的代码处理实体失败中受益,那么就是。

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

答案 3 :(得分:5)

而不是使用:

public Class EntityNotFoundException<T extends EntityBaseClass> extends Exception {

}

您应该使用:

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

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

    . . .
}

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

throw new EntityNotFoundException(Customer.class);

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

答案 4 :(得分:0)

我想每个人都回答说你不需要特定的例外。我在看Hibernate如何定义未发现的异常。我发现EntityNotFoundException我想补充一点,你甚至不应该创建自己的异常,只需重用这个异常即可。它扩展了RuntimeException,这意味着你不会强迫人们捕获它。但是,如果您愿意,可以重用J2EE中的现有类。这总是比编写新代码更好。