我应该在flatMap中对基于I/O的流使用try-with-resource吗? [英] Should I use try-with-resource in flatMap for an I/O-based stream?

查看:68
本文介绍了我应该在flatMap中对基于I/O的流使用try-with-resource吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Stream AutoCloseable ,如果基于I/O,则应在 try-with-resource 块中使用.通过 flatMap()插入的基于中间I/O的流怎么样?示例:

A Stream is an AutoCloseable and if I/O-based, should be used in a try-with-resource block. What about intermediate I/O-based streams which are inserted via flatMap()? Example:

try (var foos = foos()) {
   return foos.flatMap(Foo::bars).toArray(Bar[]::new);
}

vs.

try (var foos = foos()) {
  return foos.flatMap(foo -> {
    try (var bars = foo.bars()) {
      return bars;
    }
  }).toArray(Bar[]::new);
}

flatMap()文档说:

每个映射流在将其内容放入此流之后都将关闭.

Each mapped stream is closed after its contents have been placed into this stream.

好吧,那是幸福的道路.如果两者之间发生异常怎么办?然后,该流会保持封闭状态并潜在地泄漏资源吗?然后,我是否还应该对中间流始终使用 try-with-resource ?

Well, that's the happy path. What if there happened an exception in between? Would that stream then stay unclosed and potentially leaking resources? Should I then always use a try-with-resource also for intermediate streams?

推荐答案

像这样的构造没有意义

return foos.flatMap(foo -> {
    try (var bars = foo.bars()) {
        return bars;
    }
}).toArray(Bar[]::new);

因为那样会在之前关闭流,将其返回给调用者,这将使子流完全不可用.

as that would close the stream before it is returned to the caller, which makes the sub-stream entirely unusable.

实际上,函数代码无法确保关闭将在函数外部的适当位置进行.这肯定是API设计人员决定不必这样做的原因,并且Stream实施会引起注意.

In fact, it is impossible for the function’s code to ensure that the closing will happen at the appropriate place, which is outside the function. That’s surely the reason why the API designers decided that you don’t have to, and the Stream implementation will take care.

这也适用于特殊情况.一旦函数将其返回给Stream,Stream仍将确保关闭流:

This also applies to the exceptional case. The Stream still ensures that the stream gets closed, once the function has returned it to the 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.

You may play with the conditions, to see that a constructed Stream is always closed. For elements of the outer Stream which do not get processed, there will be no Stream at all.

对于像 .flatMap(Foo :: bars) .flatMap(foo-> foo.bars())之类的Stream操作,您可以假定 bars()成功创建并返回了Stream,它将被传递给调用方以确保正确关闭.

For a Stream operation like .flatMap(Foo::bars) or .flatMap(foo -> foo.bars()), you can assume that once bars() successfully created and returned a Stream, it will be passed to the caller for sure and properly closed.

另一种情况是映射函数,这些函数在Stream创建后执行可能会失败的操作,例如

A different scenario would be mapping functions which perform operations after the Stream creation which could fail, e.g.

.flatMap(foo -> {
    Stream<Type> s = foo.bar();
    anotherOperation(); // Stream is not closed if this throws
    return s;
})

在这种情况下,有必要确保在特殊情况下关闭,但仅在特殊情况下:

In this case, it would be necessary to ensure the closing in the exceptional case, but only in the exceptional case:

.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,在这种情况下,您不需要这种保护.

but obviously, you should follow the general rule to keep lambdas simple, in which case you don’t need such protection.

这篇关于我应该在flatMap中对基于I/O的流使用try-with-resource吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆