我正在创建多个流,我必须并行(或可能并行)访问。我知道如何在编译时修复资源量时尝试使用资源,但是如果资源量由参数确定怎么办?
我有这样的事情:
private static void foo(String path, String... files) throws IOException {
@SuppressWarnings("unchecked")
Stream<String>[] streams = new Stream[files.length];
try {
for (int i = 0; i < files.length; i++) {
final String file = files[i];
streams[i] = Files.lines(Paths.get(path, file))
.onClose(() -> System.out.println("Closed " + file));
}
// do something with streams
Stream.of(streams)
.parallel()
.flatMap(x -> x)
.distinct()
.sorted()
.limit(10)
.forEach(System.out::println);
}
finally {
for (Stream<String> s : streams) {
if (s != null) {
s.close();
}
}
}
}
答案 0 :(得分:5)
您可以编写一个复合AutoCloseable
来管理动态数量的AutoCloseable
:
import java.util.ArrayList;
import java.util.List;
public class CompositeAutoclosable<T extends AutoCloseable> implements AutoCloseable {
private final List<T> components= new ArrayList<>();
public void addComponent(T component) { components.add(component); }
public List<T> getComponents() { return components; }
@Override
public void close() throws Exception {
Exception e = null;
for (T component : components) {
try { component.close(); }
catch (Exception closeException) {
if (e == null) { e = closeException; }
else { e.addSuppressed(closeException); }
}
}
if (e != null) { throw e; }
}
}
你可以在你的方法中使用它:
private static void foo(String path, String... files) throws Exception {
try (CompositeAutoclosable<Stream<String>> streams
= new CompositeAutoclosable<Stream<String>>()) {
for (int i = 0; i < files.length; i++) {
final String file = files[i];
streams.addComponent(Files.lines(Paths.get(path, file))
.onClose(() -> System.out.println("Closed " + file)));
}
streams.getComponents().stream()
.parallel()
.flatMap(x -> x)
.distinct()
.sorted()
.limit(10)
.forEach(System.out::println);
}
}
答案 1 :(得分:1)
documentation of Stream.flatMap
说:
每个映射的流在将其内容放入此流后将关闭。
换句话说,对于流的普通关闭,不需要额外的动作。但是,由于只关闭了已处理的流,因此您不应急切地创建流,而不知道它们是否稍后由流处理:
private static void foo(String path, String... files) throws IOException {
Arrays.stream(files).flatMap(file-> {
try { return Files.lines(Paths.get(path, file))
.onClose(() -> System.out.println("Closed " + file)); }
catch(IOException ex) { throw new UncheckedIOException(ex); } })
.parallel()
.distinct()
.sorted()
.limit(10)
.forEachOrdered(System.out::println);
}
通过在flatMap
内创建子流,可以保证每个子流只在流处理它时才会创建。因此,即使没有使用try-with-resource语句中的外部Stream
,此解决方案也将关闭所有子流。