有没有一种正确的方法来为集合中的每个元素打开资源,而不是使用流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来完成。
答案 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