好模式? <x extends =“”exception =“”> ... method()抛出X </x>

时间:2014-02-09 00:53:34

标签: java exception generics throws checked-exceptions

一些背景,然后是一些问题。

我最近才发现接口(或类)在其方法可能引发的(已检查)异常类型中可能是通用的。例如:

interface GenericRunnable<X extends Exception> {
    void run() throws X;
}

关键是如果您稍后使用IOException实例化并调用run方法,则编译器知道您需要捕获IOException或将其标记为抛出。更好的是,如果XRuntimeException,则根本不需要处理它。

这是一个使用上述界面的人为例子,但它基本上是一个回调,应该很常见。

public <X extends Exception> void runTwice(GenericRunnable<X> runnable) throws X {
    runnable.run(); runnable.run();
}
...
public myMethod() throws MyException {
    runTwice(myRunnable);
}

我们正在调用通用实用程序方法runTwice(可能在外部库中定义)以使用特定的已检查异常运行我们自己的特定方法,并且我们不会丢失有关哪个特定已检查异常可能的信息被抛出。

替代方法是在throws Exception方法和Runnable.run方法上使用runTwice。这不会限制Runnable接口的任何实现,但是检查异常的优势将会丢失。或者根本没有throws,也失去了检查异常的优势,并可能迫使实现包装。

因为我从未见过throws X,也许我错过了一些东西。此外,我已经看到回调示例多次用作针对已检查异常的参数,而不会被反驳。 (这个问题对检查异常的利弊不感兴趣。)

throws X通常是个好主意吗?优缺点都有什么?您能否提供一些使用throws X或没有但应该使用的示例?

基本上,我想进一步了解一下。您可以对以下示例发表评论。

  • OutputStream抛出IOException(也许ByteArrayOutputStream可以延伸GenericOutputStream<RuntimeException>

  • Callable / Future.get

  • Commons Pool borrowObject / makeObject

(自编辑以来,我不会问这些是否/应该在回顾时采用不同的设计。相反,throws X会优于throws Exception。)

1 个答案:

答案 0 :(得分:3)

我一直使用这种模式,主要用于函数式java。

优点:

  1. 你可以有几种类型的高阶模式,比如访问者:

    interface ExceptionalVoidVisitor< E extends Exception > {
        void handleA( A a ) throws E;
        void handleB( B b ) throws E;
    }
    interface VoidVisitor extends ExceptionalVoidVisitor< RuntimeException > {}
    interface ExceptionalVisitor< T, E extends Exception > {
        T handleA( A a ) throws E;
        T handleB( B b ) throws E;
    }
    interface Visitor< T > extends ExceptionalVisitor< T, RuntimeException > {}
    
  2. 您的客户端可以为他可能抛出的所有异常声明一个基本异常类,最终会得到一个完全通用的库。

  3. 缺点:

    1. 正如您所发现的那样,无法处理泛型类型的异常;你必须让它逃脱。
    2. 另一个选择是接受E的生成器,这对客户来说可能很尴尬。