关于输入输出流的惯用法

书上说,应该坚持“谁打开的谁负责关闭”的原则。
比如这样一个函数 void f(InputStream ins) {...}
因为ins不是在f里面打开的,所以不应该在f里面关掉f

比如,ins是在main里面打开的,那么应该这样用
main() {
InputStream ins = new ...;
f(ins);
ins.close();
}

但是如果一个Stream是作为构造函数的参数传进去的话:
class Parser {
BufferedReader ins;
Parser(BufferedReader ins) { this.ins = ins; }
Entry parseNext() {//read from ins}
...
}

假设Parse还有另一个构造函数的话, 便于直接从文件读取:
Parser(String fileName) {
ins = new BufferedReader(new FileReader(fileName));
}
那么这个ins应该在什么地方关闭呢? 显然不应该在构造函数里面,因为parseNext的时候还要用到ins。

应该在parseNext里面吗?在解析完最后一个entry之后关闭? 这样也不行,因为用户可能只需要前一两个entry, 这样的话ins就永远不会关闭了。

或者就不应该提供一个Parser(String)这样的便利构造函数, 每次都要由用户自己提供一个 new BufferedReader(new FileReader(fileName)), 这样的话岂不是太麻烦?

即使是提供了一个
BufferedReader open(String fileName) { return new BufferedReader(new FileReader(fileName)); }
之类的辅助函数,用起来仍然比较麻烦:
BufferedReader ins = FileUtil.open(fileName);
Parser p = new Parser(ins); //....
并不比这种写法方便多少:
BufferedReader ins = new BufferedReader(new FileReader(fileName));
Parser p = new Parser(ins);//....
显然没有这样方便: Parser p = new Parser(fileName); 但是这样又会存在上面说的问题。

不知道标准的做法应该是什么样子的呢?

还有,函数的参数是应该尽量抽象,比如Reader,然后在函数里面包装成一个BufferedReader
还是应该尽量具体呢,比如直接限定函数类型为BufferedReader

另外就是关于IOException的异常处理,是应该尽量在函数里面捕获异常呢,还是应该将其抛出?

一般情况是在一个方法里打开,不管怎么用,都在这个方法里面关闭。
或者如果inputStream是一个类的成员变量,那就在这个类销毁的时候关闭,比如写一个destory方法。
而如果你的一个类需要一个inputStream,而且需要由多个地方调用,实在没有适合的地方去关闭,那建议你不要由外部传进去inputStream,而是传进去你需要使用的inputStream的class,然后由你的那个类构造方法创建,最后手动destroy。

最后你的异常问题,主要是看你需要在哪里捕获,例如你serviceImpl里面有一个方法,返回值是int,那么你就不能在这里捕获,因为你无法传回异常状态,此时应该在调用这个serviceImpl的地方捕获。同时也有多级捕获的时候,也有让例如struts2自动捕获的时候,看情况吧。

加一个boolean的全局变量,记录inputStream是传进来的,还是自己创建的。然后在关闭的代码前用此boolean值进行判断是否要close()