在Java中生成致命错误

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分配符合标准,则永远不会达到.

但如果不是呢?如何以最正确的方式处理此异常?问题是,如何正确警告这种错误?

建议是:

  1. 扔了某种东西RuntimeException.
  2. 不要在生产代码中禁用记录器,在日志中写入异常详细信息并忽略它.
  3. 放在assert false这里,如果用户启动了VM,它会产生AssertionError -ea.
  4. AssertionError手动投掷.
  5. 添加UnsupportedEncodingExceptionin方法声明并允许用户选择.我觉得不太方便.
  6. 打电话System.exit(1).

谢谢.

Jon*_*eet 7

但如果不是呢?

然后你处境非常糟糕,你应该尽可能快地摆脱它.当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)用:)开始(如果你还没有使用番石榴,现在是一个好时机,开始...)

  • 我想在这个答案的每个段落给+1一次. (2认同)

Pau*_*per 6

这在代码中很常见.

未经检查的例外情况就是这样做的.它们不应该发生(这就是为什么它们没有被检查),但是如果它们发生了,那么仍然有例外.

因此,抛出一个RuntimeException原始Exception的原因.

catch (UnsupportedEncodingException e) {
    throw new RuntimeException(e); //should not happen
}
Run Code Online (Sandbox Code Playgroud)

assert(false); 还会抛出一个未经检查的异常,但它可以关闭断言,所以我建议使用RuntimeException.