本文记录Java中关闭Chained-Streams的正确方式。

在Java开发过程中,我们时常使用这样的方式创建输入输出流,如下方式1:

1
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));

或者如下方式2创建:

1
2
3
FileOutputStream fos = new FileOutputStream(...)
BufferedOS bos = new BufferedOS(fos);
ObjectOutputStream oos = new ObjectOutputStream(bos);

使用方式1时,我们仅仅使用br.close()是否会造成流资源的不正确关闭?使用方式2时,是否需要把创建的每个流(oos/bos/fos)都依次关闭呢?

当你正确使用try-with-resources时,你就没有必要显式close流资源。但是当你使用的JDK<7时,你必须总得显式使用close方法清除流资源。

一些java.io 输出类包含了flush方法,当该类调用了close方法时,它会自动调用flush方法执行,没有必要在调用close方法前显示调用flush方法。

当一个stream1通过另一个stream2的构造函数链接到stream2时,close stream2时,它会自动close底层stream1资源。如果有多个stream链接在一起(如上方式1、方式2),那么关闭最后创建的stream,它将会自动关闭所有底层的stream资源。

以下是正确关闭流的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package org.readus.stream;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;

public class CloseStream {

/** JDK before version 7. */
@SuppressWarnings("unchecked")
public static void main(String[] args) {
// create a Serializable List
List<String> quarks = Arrays.asList("up", "down", "strange", "charm",
"top", "bottom");

// serialize the List
// note the use of abstract base class references
try {
// use buffering
OutputStream file = new FileOutputStream("quarks.ser");
OutputStream buffer = new BufferedOutputStream(file);
ObjectOutput output = new ObjectOutputStream(buffer);
try {
output.writeObject(quarks);
} finally {
output.close();
}
} catch (IOException ex) {
// ex.printStackTrace();
System.out.println("Cannot perform output: " + ex);
}

// deserialize the quarks.ser file
// note the use of abstract base class references
try {
// use buffering
InputStream file = new FileInputStream("quarks.ser");
InputStream buffer = new BufferedInputStream(file);
ObjectInput input = new ObjectInputStream(buffer);
try {
// deserialize the List
List<String> recoveredQuarks = (List<String>) input
.readObject();
// display its data
for (String quark : recoveredQuarks) {
System.out.println("Recovered Quark: " + quark);
}
} finally {
input.close();
}
} catch (ClassNotFoundException ex) {
// ex.printStackTrace();
System.out.println("Cannot perform input. Class not found: " + ex);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

参考:

Always close streams