如何处理永远不会抛出的检查异常


35

例:

foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");

由于编码是经过硬编码且正确的,因此构造函数将永远不会抛出规范中声明的UnsupportedEncodingException(除非Java实现被破坏,否则无论如何我都会迷路)。无论如何,Java仍然迫使我处理该异常。

目前看来

try {
    foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");
}
catch(UnsupportedEncodingException e) { /* won't ever happen */ }

任何想法如何使它变得更好?


4
对于一个真正的挑战,编写一个单元测试以确保该捕获确实有效。
杰伊·埃尔斯顿

1
`抛出新的ImpossibleException(“重新启动宇宙。事情搞砸了”,e);
克里斯·库德莫

1
“永远不会发生” ...

ThorbjørnRavn Andersen:可能在更改程序后,但是至少在当前状态下,没有一组输入数据可以触发异常。
user281377

在上面的特定示例中,抛出异常是因为该方法不知道将使用受支持的编码还是不受支持的编码调用该方法。解决该问题的方法是,如果有另一个构造函数假定已给出标准字符集,则无需声明将引发异常。
约旦2014年

Answers:


27

我的习惯是,为了安全起见,将钓丝assert放入鱼钩中。try稍后有人可能会更改该块的内容,您确实想知道代码是否失败,不是吗?


好主意; 一个简单的assert false;操作不会增加太多混乱,并且很清楚地表明我假设永远不会输入catch块。
2011年

5
@ammoQ,或者您甚至可以添加一条消息以使您的意图绝对清晰:assert false : "should never happen"
彼得Török

13
更好的是,“永远不会发生,因为Java要求支持字符集ISO-8859-1。”
dan04 2011年

3
assert表示断言已启用。我抛出了一个UnexpectedException(这还有让我拥有堆栈跟踪的好处...)。
印章

35

如果每次看到日志或错误时都得到一分钱,“这绝不应该发生”,我将……两分钱。但是...

空的捕获块使我的蜘蛛感到麻木,并且大多数好的代码分析器工具都抱怨。我将不惜一切代价避免将它们留空。当然,现在您知道该错误永远不会发生,但是从一年以后,有人在全球范围内进行了“ ISO-8859-1”的替换,您突然可能会很难发现一个错误。

assert false建议很好,但是由于可以在运行时禁用断言,因此不能保证。我会RuntimeException改用。那些将不必通过调用类来捕获,如果它们发生了,您将具有堆栈跟踪以提供完整的信息。


28

我一直这样做:

try {
    foobar = new InputStreamReader(p.getInputStream(), "ISO-8859-1");
} catch(UnsupportedEncodingException e) {
    throw new AssertionError(e);
}

可能有点冗长(Java是...),但是至少当不可能发生时,您会得到一个断言错误。

如果Java实现被破坏,您将希望尽快获得尽可能好的错误消息,而不仅仅是忽略不可能的事情。即使Java实现没有中断,也可能有人将您的代码更改为"UTF8"(糟糕-应该"UTF-8"吗?)。

首先,这应该是运行时异常。JDK充满了这种错误的选择。


4
真正糟糕的决定(或者如果您愿意,可以忽略)是Java所需的这6个字符集没有预定义的字符集实例。foobar = new InputStreamReader(p.getInputStream(), Charset.ISO_8859_1);-现在不是更好,避免一劳永逸吗?
user281377 2011年

3
番石榴图书馆拥有大量此类物品。使生活更轻松。

3
Java 1.7+确实定义了字符集常量:docs.oracle.com/javase/7/docs/api/java/nio/charset/…。像这样使用它们:StandardCharsets.UTF_8.displayName()
Michael

4

如果您是唯一会看到此代码的开发人员,那么我会说好的,但是如果您不是,那么我会将其视为一种实际可能性,或者至少将“永不发生”注释更改为一些更有用的东西。


4

这些异常让我最烦恼的部分是它损害了我的代码覆盖范围。

当我对覆盖范围感到不满时,我将汇总“永远不会发生”(...或仅当我使用以某种方式忘记包括“ US-ASCII”的突变型JVM)时进行的try / catch一个封装尝试/捕获并以此处提到的方法之一替换已检查的异常的类和方法(通常使用snide消息引发未检查的异常)。

然后,我的代码覆盖率在实用程序类中引起了轰动,但并非遍及我的代码的所有对该操作的引用。

有时,我会花一些时间像实际具有连贯语义的类中的操作那样汇总。但是由于对我的队友来说很明显,这是怎么回事,所以我通常尽可能地保持简单,并且不必担心最佳设计。

但是,正如评论所提到的那样,Guava和其他库都有减轻这种痛苦的方法-但这基本上是相同的策略。将烦恼移到舞台外,这样您的主代码就不会受到影响。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.