好图案? <X extends Exception> ... method() 抛出 X
Posted
技术标签:
【中文标题】好图案? <X extends Exception> ... method() 抛出 X【英文标题】:Good pattern? <X extends Exception> ... method() throws X 【发布时间】:2014-03-06 09:39:27 【问题描述】:一些背景,然后是一些问题。
我最近才发现接口(或类)在其方法可能抛出的(已检查)异常类型中可能是通用的。例如:
interface GenericRunnable<X extends Exception>
void run() throws X;
关键是,如果您稍后使用 IOException
实例化它并调用 run
方法,编译器知道您需要捕获 IOException
或将其标记为已抛出。更好的是,如果 X
是 RuntimeException
,那么您根本不需要处理它。
这是一个使用上述接口的人为示例,但它基本上是一个回调,应该很常见。
public <X extends Exception> void runTwice(GenericRunnable<X> runnable) throws X
runnable.run(); runnable.run();
...
public myMethod() throws MyException
runTwice(myRunnable);
我们正在调用通用实用程序方法runTwice
(可能在外部库中定义)来运行我们自己的具有特定检查异常的特定方法,并且我们不会丢失任何有关可能抛出特定检查异常的信息.
替代方法是在Runnable.run
方法和runTwice
方法上简单地使用throws Exception
。这不会限制Runnable
接口的任何实现,但会失去检查异常的优势。或者根本就没有throws
,也失去了检查异常的优势,并可能强制实现包装。
因为我从未见过throws X
,也许我错过了什么。此外,我已经多次看到回调示例用作反对检查异常的参数而没有被反驳。 (这个问题对检查异常的优缺点不感兴趣。)
throws X
通常是个好主意吗?优缺点都有什么?您能否举一些使用throws X
或未使用但应该使用的示例?
基本上,我想要一些进一步的见解。您可以对以下示例发表评论。
OutputStream
抛出IOException
(也许ByteArrayOutputStream
可以扩展GenericOutputStream<RuntimeException>
)
Callable
/Future.get
公共池borrowObject
/ makeObject
(自编辑以来,我不是在问这些是否可以/应该在回溯中进行不同的设计。而是throws X
会比throws Exception
更好。)
【问题讨论】:
流类不能这样设计,因为它们是在添加此功能之前设计的(即泛型)。 Guava 的Throwables
有一些例子。但这个问题似乎太笼统了。尝试将您在整个帖子中的各种问题提炼成更有针对性的问题。
是的。 Java随着时间的推移而发展。这意味着在较旧的类/功能中总会有一些地方可以使用较新的类/功能,但不可用——而且由于没有它们,事情就足够好,所以没有' t 是这样做的充分理由。您当然可以实现自己的旧类的包装器/重新发明以使用新功能,如果它们实际上证明足够有用,它们可能会被采用;这实际上是 Java 库增长方式的一部分。但这只有在有足够的实际附加值和足够的需求来证明它的合理性时才会发生。
@keshlam 这样做时“没有破损”..
泛型的一个缺点是您需要非常小心地设计类和 API,以便您可以保留类型。将 1 个以上的 Generic我一直使用这种模式,主要用于函数式 Java。
优点:
您可以使用多种高阶模式,例如访问者,即:
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 >
您的客户可以为他可能抛出的所有异常声明一个基异常类,您最终会得到一个完全通用的库。
缺点:
-
正如您所发现的,没有办法处理泛型类型的异常。你必须让它逃跑。
另一种选择是接受 E 的生成器,这对客户来说可能很尴尬。
【讨论】:
很高兴听到这对您来说是常见的模式。我以后不会担心自己使用它。以上是关于好图案? <X extends Exception> ... method() 抛出 X的主要内容,如果未能解决你的问题,请参考以下文章