以下代码是否需要包含在try-with-resources中以确保底层文件已关闭?
List<String> rows = Files.lines(inputFilePath).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud) 众所周知,Javadoc谈到了Stream
界面:
Streams有一个BaseStream.close()方法并实现AutoCloseable,但几乎所有的流实例实际上都不需要在使用后关闭.通常,只有源为IO通道的流(例如Files.lines(Path,Charset)返回的流)才需要关闭.大多数流都由集合,数组或生成函数支持,不需要特殊的资源管理.(如果流确实需要关闭,则可以在try-with-resources语句中将其声明为资源.)
好的,但同时flatMapToInt
在这个界面中有类似的方法:
IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
Run Code Online (Sandbox Code Playgroud)
Javadoc规范说:
每个映射的流在其内容放入此流后关闭.
所以,我没有想到:如果IntStream
没有设计在他的源代码中有IO通道,为什么它在这个方法中关闭?
例如,ReferencePipeline
实现以这种方式执行:
try (IntStream result = mapper.apply(u)) {
if (result != null)
result.sequential().forEach(downstreamAsInt);
}
Run Code Online (Sandbox Code Playgroud)
更普遍的问题可能是:我们是否应该关注像IntStream
(或其后代)那样关闭流?如果没有,那为什么要flatMapTo*
关心?
编辑 @Tunaki提供了非常有趣的电子邮件链接.但这一切都是关于flatMap
,我同意我们应该在一般情况下关闭流.但我的问题是关于特殊情况:flatMapToInt
,flatMapToLong
等等,在这里我没有看到收盘流的任何必要性.
EDIT-2 @BrianGoetz在这里上诉,因为这是他引用的电子邮件,因此他在主题:)
来自文档:
Streams有一个BaseStream.close()方法并实现AutoCloseable,但几乎所有的流实例实际上都不需要在使用后关闭.通常,只有源为IO通道的流(例如Files.lines(Path,Charset)返回的流)才需要关闭.大多数流都由集合,数组或生成函数支持,不需要特殊的资源管理.(如果流确实需要关闭,则可以在try-with-resources语句中将其声明为资源.)
当我创建一个Stream<String>
使用lines()
方法时BufferedReader
,如下所示,关闭Stream
也关闭了BufferedReader
吗?
try (Stream<String> lines = new BufferedReader(new InputStreamReader(process.getInputStream())).lines()) {
// Do stuff
}
// Is the BufferedReader, InputStreamReader and InputStream closed?
Run Code Online (Sandbox Code Playgroud)
我试过的一些非常快速的测试说没有(in
字段BufferedReader
不是null
),但后来我对下面的句子感到困惑,因为这个例子也是I/O,对吧?
通常,只有源为IO通道的流(例如Files.lines(Path,Charset)返回的流)才需要关闭.
如果没有,我是否需要关闭这两个实例,或者是否BufferedReader
足够关闭?
理想情况下,我想Stream<String>
从某种方法返回一个,而不会让客户担心读者.目前,我已经创建了一个Stream
装饰器,它也关闭了阅读器,但如果没有必要,它会更容易.
我有一个CSV文件,第一行包含标题.所以我认为使用Java 8流是完美的.
try (Stream<String> stream = Files.lines(csv_file) ){
stream.skip(1).forEach( line -> handleLine(line) );
} catch ( IOException ioe ){
handleError(ioe);
}
Run Code Online (Sandbox Code Playgroud)
是否可以获取第一个元素,分析它然后调用forEach方法?就像是
stream
.forFirst( line -> handleFirst(line) )
.skip(1)
.forEach( line -> handleLine(line) );
Run Code Online (Sandbox Code Playgroud)
另外:我的CSV文件包含大约1k行,我可以并行处理每一行以加快速度.除了第一行.我需要在我的项目中初始化其他对象的第一行:/所以也许打开BufferedReader,读取第一行,关闭BufferedReader并使用并行流是快速的?
Java 8 完成后会Stream.iterator()
自动关闭流吗?我想不是...
我有这样的事情:
class Provider implements Serializable {
Iterator<String> iterator() {
Stream<String> stream = new BufferedReader(...).lines();
return stream.iterator();
}
}
Run Code Online (Sandbox Code Playgroud)
这个迭代器被其他一些不知道迭代器基于文件读取资源的类使用。那是
class Consumer {
void f() {
Iterator<String> iterator = provider.iterator();
// code that calls iterator methods at non-determined times
}
}
Run Code Online (Sandbox Code Playgroud)
我必须流式传输文件,因为它太大而无法放入内存。但是我希望能够在迭代器没有更多元素时自动关闭资源,这样我就不会泄漏资源。该Provider
班是Serializable
,我不能有任何的流或BufferedReader中的成员。
有没有好的方法可以做到这一点?
假设每个T对象都可以实例化为
T tobj = new T(//int value);
Run Code Online (Sandbox Code Playgroud)
因此,要在由空格分隔的文件中从整数创建T []数组,请执行以下操作:
BufferedReader br;
FileReader fr;
int[] arr;
try{
fr = new FileReader(fo); // assume "fo" file name
br = new BufferedReader(fr);
arr = Arrays.stream(br.readLine().split("\\s")).mapToInt(Integer::parseInt).toArray();
}catch(SomeException e){//something else}
T[] tobjarr = new T[arr.length];
for(int i=0; i<arr.length; ++i)){
tobjarr[i] = new T(arr[i]);
}
Run Code Online (Sandbox Code Playgroud)
1.上述方法在时间和空间使用方面是否有效?
2.还有其他办法吗?如果是这样,它与上述方法相比如何?
如果我有一个java.util.Stream
需要关闭的(一旦完成),我如何才能既关闭它(通过调用close
)又调用一个终端操作,如count
or collect
?
例如:
java.nio.file.Files.lines(FileSystems.getDefault().getPath("myfile.txt"))
.collect(Collectors.toSet());
//.close(); ???
Run Code Online (Sandbox Code Playgroud)
(在此示例中,调用close并不重要,但可以说我有一个Stream对象,该对象通过onClose在流中注册了关键的close操作)。
我猜您可以将流存储在temp var中并关闭它,如下所示:
Stream<String> ss = java.nio.file.Files.lines(FileSystems.getDefault().getPath("myfile.txt"));
Set<String> lines = ss.collect(Collectors.toSet());
ss.close();
return lines;
Run Code Online (Sandbox Code Playgroud)
但似乎有点笨拙。以这种方式关闭流是否总是安全的?