有没有正确的方法来关闭在Java流api中打开的资源(针对每个元素)?

时间:2019-04-17 22:04:07

标签: java resources java-stream autocloseable

有没有一种正确的方法来为集合中的每个元素打开资源,而不是使用流api,是否使用该资源来执行一些map(),filter(),peek()等操作,然后关闭该资源?

我有这样的事情:

List<String> names =  getAllNames();
names.stream().map(n -> getElementFromName(n))
              .filter(e -> e.someCondition())
              .peek(e -> e.doSomething())
              .filter(e -> e.otherCondition())
              .peek(e -> e.doSomethingElse())
              .filter(e -> e.lastCondition())
              .forEach(e -> e.doTheLastThing());

这应该工作正常,除了我要在getElementFromName方法中打开资源(例如db连接)。然后,我正在其他实例方法(例如someCondition或doSomething)中使用该资源。而且我不知道如何正确关闭它。

我知道,我只在流上使用中间操作。这意味着,所有方法都可以在forEach操作中进行评估,并且性能应该可以,因为迭代仅执行一次。

但是我不知道如何关闭为getElementFromName方法中的每个元素打开的资源。

我可以保存由getElementFromName创建的所有元素的列表,并在以后关闭资源。但是我只是在浪费空间,让所有资源都活着。此外,还将通过元素列表进行第二次迭代。在这种情况下,最好避免使用流api。那么当我使用完元素后,有什么办法可以自动关闭资源吗?

我也知道,可以使用foreach lopp轻松完成它,我只是好奇是否可以使用流api来完成。

2 个答案:

答案 0 :(得分:3)

您可以使用flatMap

.flatMap(n -> {
    YourResource r = getElementFromName(n);
    return Stream.of(r).onClose(r::close);
})

这假设返回元素封装的资源具有close()方法。如果不是这样,代码将变得更加复杂,但是图片应该清晰。您返回的不是单元素流,而是返回其onClose操作进行必要清理的单元素流。如果它可以引发已检查的异常,则还必须为此添加处理程序,最好将异常包装在未检查的异常中。

这取决于对flatMap所做的保证:

  

每个映射流都将closed的内容放入该流之后。

但是通常,此代码(尤其是过度使用peek)看起来非常可疑。

答案 1 :(得分:0)

您可以创建第二个列表来存储遇到的元素。不幸的是,这是我知道的使用流关闭所有元素的唯一方法。

在此示例中,我假设getElementFromName返回类型为Element的对象:

List<Element> elements = new ArrayList<>(); // Or whatever kind of list you want
List<String> names =  getAllNames();
names.stream().map(n -> getElementFromName(n))
              .peek(e -> elements.add(e)) // Add the elements to the list
              .filter(e -> e.someCondition())
              .peek(e -> e.doSomething())
              .filter(e -> e.otherCondition())
              .peek(e -> e.doSomethingElse())
              .filter(e -> e.lastCondition())
              .forEach(e -> e.doTheLastThing());

elements.forEach(e -> e.close()); // Close all the elements