是否有正确的方法来关闭在 java 流 api 中打开的资源(对于每个元素)?
Is there a correct way to close resources opened in java stream api (for each element)?
是否有正确的方法为集合中的每个元素打开资源,而不是使用流 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 方法中打开资源(例如数据库连接)。然后我在其他实例方法(如 someCondition 或 doSomething)中使用该资源。而且我不知道如何正确关闭它。
我知道,我只对流使用中间操作。这意味着,所有方法都在 forEach 操作中评估,性能应该没问题,因为迭代只完成一次。
但是我不知道如何关闭为 getElementFromName 方法中的每个元素打开的资源。
我可以保存由 getElementFromName 创建的所有元素的列表,稍后关闭资源。但我只会浪费 space,让所有资源保持活力。此外,还会对元素列表进行第二次迭代。在这种情况下,这使得避免流 api 更可取。那么有没有办法在我使用完元素后以某种方式自动关闭资源?
我也知道,使用 foreach lopp 可以轻松完成,我只是好奇是否可以使用流 api.
您可以创建第二个列表来存储您遇到的元素。不幸的是,这是我所知道的使用流关闭所有元素的唯一方法。
在这个例子中,我将假设 getElementFromName
return 的一个对象输入 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
你可以使用 flatMap
:
.flatMap(n -> {
YourResource r = getElementFromName(n);
return Stream.of(r).onClose(r::close);
})
这里假设返回元素封装的资源有close()
方法。如果没有,代码会变得更复杂,但图片应该很清楚。您不只是返回单个对象,而是返回一个单元素流,其 onClose
操作执行必要的清理。如果它可以抛出已检查的异常,您还必须为此添加一个处理程序,最好将异常包装在未检查的异常中。
这依赖于flatMap
的保证:
Each mapped stream is closed
after its contents have been placed into this stream.
但总的来说,这段代码,尤其是 的过度使用,看起来非常可疑。
是否有正确的方法为集合中的每个元素打开资源,而不是使用流 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 方法中打开资源(例如数据库连接)。然后我在其他实例方法(如 someCondition 或 doSomething)中使用该资源。而且我不知道如何正确关闭它。
我知道,我只对流使用中间操作。这意味着,所有方法都在 forEach 操作中评估,性能应该没问题,因为迭代只完成一次。
但是我不知道如何关闭为 getElementFromName 方法中的每个元素打开的资源。
我可以保存由 getElementFromName 创建的所有元素的列表,稍后关闭资源。但我只会浪费 space,让所有资源保持活力。此外,还会对元素列表进行第二次迭代。在这种情况下,这使得避免流 api 更可取。那么有没有办法在我使用完元素后以某种方式自动关闭资源?
我也知道,使用 foreach lopp 可以轻松完成,我只是好奇是否可以使用流 api.
您可以创建第二个列表来存储您遇到的元素。不幸的是,这是我所知道的使用流关闭所有元素的唯一方法。
在这个例子中,我将假设 getElementFromName
return 的一个对象输入 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
你可以使用 flatMap
:
.flatMap(n -> {
YourResource r = getElementFromName(n);
return Stream.of(r).onClose(r::close);
})
这里假设返回元素封装的资源有close()
方法。如果没有,代码会变得更复杂,但图片应该很清楚。您不只是返回单个对象,而是返回一个单元素流,其 onClose
操作执行必要的清理。如果它可以抛出已检查的异常,您还必须为此添加一个处理程序,最好将异常包装在未检查的异常中。
这依赖于flatMap
的保证:
Each mapped stream is
closed
after its contents have been placed into this stream.
但总的来说,这段代码,尤其是