6

假设我们正在编写一个 Java 库,它提供了一些 I/O 实用功能,例如,一种将文本文件读取为字符串的便捷方法:

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(byte[], String)构造函数会抛出异常。UnsupportedEncodingException但是,正如我们所知,ISO-8859-1必须由 JRE 支持,如此处所述(参见标准字符集部分)

因此,我们期望区块

catch (UnsupportedEncodingException e) {
    log.fatal("encoding is unsupported", e);
    // ???
}

如果 JRE 分发符合标准,则永远不会达到。

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

建议是:

  1. 抛出某种RuntimeException.
  2. 不要在生产代码中禁用记录器,在日志中写入异常详细信息并忽略它。
  3. assert false它放在这里,所以如果用户使用-ea.
  4. AssertionError手动抛出一个。
  5. 添加一个UnsupportedEncodingExceptionin 方法声明并允许用户选择。不是很方便,我想。
  6. 打电话System.exit(1)

谢谢。

4

2 回答 2

9

但如果没有呢?

那么你就处于非常糟糕的境地,你应该尽快摆脱困境。当 JRE 违反了自己的承诺时,您希望依赖什么?

AssertionError在这种情况下我会很高兴使用。

需要注意的是,并非所有未经检查的异常都得到同等对待 - 代码Exception在堆栈的顶层捕获,记录错误然后继续运行并不罕见......如果你只是 throw RuntimeException,那被这样的方案。AssertionError只有在指定了 catch 块时才会被捕获Throwable(或者特别是Erroror AssertionError,但这种情况很少见)。鉴于这应该是多么不可能,我认为真的很难中止是合理的。

另请注意,在 Java 7 中,您可以使用StandardCharsets.ISO_8859_1字符串名称来代替,这样更简洁并消除了问题。

顺便说一句,我还有其他关于您的代码的更改:

  • 我会尽量避免使用available()这告诉你现在有多少字节可用- 它不一定告诉你文件有多长。
  • 绝对不会假设它read()会一口气读完整个文件。循环调用read(),理想情况下,直到它说没有更多数据为止。
  • 我个人会接受 aCharset作为参数,而不是硬编码 ISO-8859-1。- 我会IOException从方法中冒泡,而不是仅仅返回null。毕竟,除非你真的要检查每个调用的返回值是否为 null,否则你只会得到 aNullPointerException而不是,这比原来的 . 更难诊断IOException

或者,只需使用GuavaFiles.toString(File, Charset)开始 :) (如果您还没有使用 Guava,现在是开始的好时机...... )

于 2013-10-29T07:04:56.630 回答
7

这是代码中相当常见的情况。

未经检查的例外是为此。它们不应该发生(这就是它们未被检查的原因),但如果它们发生了,仍然存在异常。

所以,抛出一个RuntimeException以原来Exception为因的。

catch (UnsupportedEncodingException e) {
    throw new RuntimeException(e); //should not happen
}

assert(false);也会抛出未经检查的异常,但它的断言可以关闭,所以我会推荐 RuntimeException。

于 2013-10-29T07:03:40.143 回答