假设我们正在编写一个Java库,它提供了一些I / O ulitity函数,例如,一个方便的方法来读取文本文件作为字符串:
public class StringReader {
private static final Logger log = LoggerFactory.getLog(StringReader.class);
/**
* Returns the contents of file <b>fileName</b> as String.
* @param fileName file name to read
* @return null on IO error
*/
public static String readString(String fileName) {
FileInputStream fis = null;
try {
fis = new FileInputStream(fileName);
byte[] data = new byte[fis.available()];
fis.read(data);
return new String(data, "ISO-8859-1"); // may throw UnsupportedEncodingException!
} catch (IOException e) {
log.error("unable to read file", e);
} catch (UnsupportedEncodingException e) {
log.fatal("JRE does not support ISO-8859-1!", e);
// ???
} finally {
closeQuiet(fis);
}
return null;
}
}
此代码使用ISO-8859-1编码将文本文件读入String,并将String返回给用户。
String(byte[], String)
构造函数在不支持指定编码时抛出UnsupportedEncodingException
。但是,正如我们所知,ISO-8859-1
必须得到JRE的支持,如here (see the Standard charsets section)所述。
因此,我们期待块
catch (UnsupportedEncodingException e) {
log.fatal("encoding is unsupported", e);
// ???
}
如果JRE分发符合标准,则永远不会达到。
但如果没有呢?如何以最正确的方式处理此异常? 问题是,如何正确警告这种错误?
建议如下:
RuntimeException
。assert false
放在此处,如果用户使用-ea
启动了VM,则会产生AssertionError。AssertionError
。UnsupportedEncodingException
并允许用户选择。我认为不太方便。System.exit(1)
。感谢。
答案 0 :(得分:7)
但如果没有呢?
然后你处境非常糟糕,你应该尽可能快地摆脱它。当JRE违反自己的承诺时, 会依赖什么?
在这种情况下,我会很高兴使用AssertionError
。
重要的是要注意并非所有未经检查的异常都被平等对待 - 代码在堆栈的顶层捕获Exception
,记录错误然后继续...并不常见...如果你只是抛出RuntimeException
,将被此类计划捕获。仅当catch块指定AssertionError
(或具体为Throwable
或Error
时才会捕获AssertionError
,但这种情况很少见。鉴于这应该是多么不可能,我认为真的很难中止是合理的。
另请注意,在Java 7中,您可以使用StandardCharsets.ISO_8859_1
而不是字符串名称,这更清晰并且可以解决问题。
顺便说一句,关于你的代码还有其他一些改变:
available()
。这告诉你现在有多少字节可用 - 它不会告诉你文件有多长,必然。read()
将一次读取整个文件。在循环中调用read()
,理想情况下直到它说没有更多数据。Charset
作为参数,而不是硬编码ISO-8859-1。 - 我会让IOException
从方法中冒出来,而不仅仅是返回null
。毕竟,除非你真的要检查每个无效调用的返回值,否则你最终会得到NullPointerException
,这比诊断更难原IOException
。或者,只需使用Guava的Files.toString(File, Charset)
开头:)(如果你还没有使用过番石榴,现在是开始的好时机......)
答案 1 :(得分:5)
这在代码中很常见。
为此进行了未经检查的例外情况。它们不应该发生(这就是为什么它们没有被检查),但如果它们发生了,那么仍有例外。
因此,请抛出原始RuntimeException
作为原因的Exception
。
catch (UnsupportedEncodingException e) {
throw new RuntimeException(e); //should not happen
}
assert(false);
也会抛出一个未经检查的异常,但它的断言可以关闭,所以我建议使用RuntimeException。