2 回答
TA贡献1828条经验 获得超13个赞
像这样的结构没有意义
return foos.flatMap(foo -> {
try (var bars = foo.bars()) {
return bars;
}
}).toArray(Bar[]::new);
因为这会在流返回给调用者之前关闭流,这使得子流完全无法使用。
事实上,函数的代码不可能确保关闭会发生在函数外部的适当位置。这肯定是 API 设计者决定您不必这样做的原因,而 Stream 实现将负责。
这也适用于特殊情况。一旦函数将流返回给流,流仍然会确保流被关闭:
try {
IntStream.range(1, 3)
.flatMap(i -> {
System.out.println("creating "+i);
return IntStream.range('a', 'a'+i)
.peek(j -> {
System.out.println("processing sub "+i+" - "+(char)j);
if(j=='b') throw new IllegalStateException();
})
.onClose(() -> System.out.println("closing "+i));
})
.forEach(i -> System.out.println("consuming "+(char)i));
} catch(IllegalStateException ex) {
System.out.println("caught "+ex);
}
creating 1
processing sub 1 - a
consuming a
closing 1
creating 2
processing sub 2 - a
consuming a
processing sub 2 - b
closing 2
caught java.lang.IllegalStateException
您可以使用条件来查看构造的 Stream 始终是关闭的。对于未处理的外部 Stream 的元素,根本不会有 Stream。
对于类似.flatMap(Foo::bars)or的 Stream 操作.flatMap(foo -> foo.bars()),您可以假设一旦bars()成功创建并返回了 Stream,它将被传递给调用者并正确关闭。
一个不同的场景是映射函数,它在 Stream 创建之后执行操作,这可能会失败,例如
.flatMap(foo -> {
Stream<Type> s = foo.bar();
anotherOperation(); // Stream is not closed if this throws
return s;
})
在这种情况下,有必要确保在例外情况下关闭,但仅在例外情况下:
.flatMap(foo -> {
Stream<Type> s = foo.bar();
try {
anotherOperation();
} catch(Throwable t) {
try(s) { throw t; } // close and do addSuppressed if follow-up error
}
return s;
})
但显然,您应该遵循一般规则来保持 lambda 简单,在这种情况下,您不需要这种保护。
TA贡献1812条经验 获得超5个赞
无论是否在 Stream 中,您都必须在相关位置关闭 IO 资源。
该flatMap()方法是通用的流方法,因此它不知道您在其中打开的 IO 资源。
但是为什么flatMap()会与任何操纵 IO 资源的方法不同呢?例如,如果您在 中操作 IO map(),如果发生异常,您可能会遇到相同的问题(不释放资源)。
关闭流(如flatMap())不会使其释放在流操作中打开的所有资源。例如
,一些方法可以做到这一点。File.lines(Path)但是如果你在 中打开了一些资源flatMap(),这些资源的关闭不会在流关闭时自动进行。
例如这里的 flatMap 处理不会关闭FileInputStream已打开:
...
.stream()
.flatMap(foo -> {
try {
FileInputStream fileInputStream = new FileInputStream("..."));
//...
}
catch (IOException e) {
// handle
}
})
您必须明确关闭它:
...
.stream()
.flatMap(foo -> {
try (FileInputStream fileInputStream = new FileInputStream("...")){
//...
} catch (IOException e) {
// handle
}
// return
})
所以是的,如果在内部使用的语句flatMap()或任何方法操作一些 IO 资源,你想在任何情况下关闭它们,用一个语句包围它try-with-resources以使它们自由。
添加回答
举报