在不丢失原始异常的情况下,在finally块中静默关闭InputStream的正确方法是什么?

Evg*_*eev 26 java

我想知道下面的代码是否正确地关闭了finally块中的InputStream

InputStream is = new FileInputStream("test");
try {
    for(;;) {
        int b = is.read();
        ...
    }
} finally {
    try {
        is.close();
    } catch(IOException e) {
    }
}
Run Code Online (Sandbox Code Playgroud)

如果在is.close()期间发生异常,则在is.read()期间发生异常将被忽略/抑制吗?

Alp*_*dar 15

最好的方法是使用Java 7并使用try with resources,或者手动执行相同的操作,并在关闭时添加异常作为抑制异常.

Pre Java 7:如果你抛出自定义异常,你可以在它中添加压缩异常,就像它在Java 7中完成一样(在你的异常创建字段列表中被禁止并在关闭操作中放置异常,并在处理异常时,查看那里如果你不能这样做,我不知道什么比记录它更好.

示例:来自Java教程

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br = new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}
Run Code Online (Sandbox Code Playgroud)

但更好的形式是:

static String readFirstLineFromFile(String path) throws IOException {
    try (FileReader fr = new FileReader(path);
         BufferedReader br = new BufferedReader(fr)) {
        return br.readLine();
    }
}
Run Code Online (Sandbox Code Playgroud)

这种方式即使FileReader的创建成功但BufferedReader的创建失败(例如内存不足),FileReader也将被关闭.


Igo*_*vić 9

您可以使用来自https://commons.apache.org/proper/commons-io/的 IOUtils关闭它

    public void readStream(InputStream ins) {

    try {
        //do some operation with stream         
    } catch (Exception ex) {
        ex.printStackTrace();           
    } finally {
        IOUtils.closeQuietly(ins);
    }       
}
Run Code Online (Sandbox Code Playgroud)

  • 请勿在IOUtils 2.6上使用,弃用和删除而无需更换。“请使用try-with-resources语句或手动处理抑制的异常。” (2认同)

flu*_*lup 7

Java 6的规格

如果try块的执行由于任何其他原因R突然完成,则执行finally块.然后有一个选择:如果finally块正常完成,那么try语句突然完成原因R.如果finally块突然完成原因S,则try语句突然完成原因S(并且原因R被丢弃).

所以你是对的,你会失去原来的例外.

解决方案可能是如此防御地编写你的finally块,如果finally块失败,那么它是一个更大的惊喜(值得传播),而不是try catch块出现异常.

因此,例如,如果在您尝试关闭它时该流可能为null,请检查它:

InputStream is = new FileInputStream("test");
try {
    for(;;) {
        int b = is.read();
        ...
    }
} finally {
    try {
        if( is!=null ) {
            is.close();
        }
    } catch(IOException e) {
    }
}
Run Code Online (Sandbox Code Playgroud)

在Java 7中,Alpedar的解决方案当然是必由之路.


mon*_*ack 3

is.close() 中的异常将被抑制,而 is.read() 中的异常将向上传播。