Sta*_*tov 6 java exception-handling
假设我们正在编写一个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;
}
}
Run Code Online (Sandbox Code Playgroud)
此代码使用ISO-8859-1编码将文本文件读入String,并将String返回给用户.
该String(byte[], String)构造函数抛出UnsupportedEncodingException不支持指定编码时.但是,正如我们所知,ISO-8859-1必须得到JRE的支持,如此处所述(参见标准字符集部分).
因此,我们期待阻止
catch (UnsupportedEncodingException e) {
log.fatal("encoding is unsupported", e);
// ???
}
Run Code Online (Sandbox Code Playgroud)
如果JRE分配符合标准,则永远不会达到.
但如果不是呢?如何以最正确的方式处理此异常?问题是,如何正确警告这种错误?
建议是:
RuntimeException.assert false这里,如果用户启动了VM,它会产生AssertionError -ea.AssertionError手动投掷.UnsupportedEncodingExceptionin方法声明并允许用户选择.我觉得不太方便.System.exit(1).谢谢.
但如果不是呢?
然后你处境非常糟糕,你应该尽可能快地摆脱它.当JRE违反了自己的承诺,是什么将要依靠?
AssertionError在这种情况下,我会感到高兴.
重要的是要注意并非所有未经检查的异常都被平等对待 - 代码捕获Exception堆栈的顶层,记录错误然后继续... 并不常见...如果你只是抛出RuntimeException,那将被这样的一个抓住方案.AssertionError只有在指定了catch块时才会被捕获Throwable(或者具体地说,Error或者AssertionError,但是很难看到).鉴于这应该是多么不可能,我认为真的很难中止.
另请注意,在Java 7中,您可以使用StandardCharsets.ISO_8859_1而不是字符串名称,这更清晰并且可以解决问题.
顺便说一句,关于你的代码我还有其他一些改变:
available().这告诉你现在有多少字节可用- 它不会告诉你文件需要多长时间.read()会一次性读取整个文件.read()在循环中调用,理想情况下直到它说没有更多数据.Charset参数,而不是硬编码ISO-8859-1.- 我会IOException从方法中冒出来,而不仅仅是返回null.毕竟,除非你真的要检查每个无效调用的返回值,否则你最终会得到一个NullPointerException代替,这比原来更难诊断IOException.另外,只要使用番石榴的Files.toString(File, Charset)用:)开始(如果你还没有使用番石榴,现在是一个好时机,开始...)
这在代码中很常见.
未经检查的例外情况就是这样做的.它们不应该发生(这就是为什么它们没有被检查),但是如果它们发生了,那么仍然有例外.
因此,抛出一个RuntimeException原始Exception的原因.
catch (UnsupportedEncodingException e) {
throw new RuntimeException(e); //should not happen
}
Run Code Online (Sandbox Code Playgroud)
assert(false); 还会抛出一个未经检查的异常,但它可以关闭断言,所以我建议使用RuntimeException.