![](/img/trans.png)
[英]Close multiple resources with AutoCloseable (try-with-resources)
[英]Close a dynamic number of AutoCloseable objects in try-with-resources
我正在try-with-resources
塊中創建可變數量的AutoCloseable
對象。 在任何退出點,我都希望關閉所有分配的資源。
我可以想象自己編寫一些東西來做到這一點,但是是否有類似於Python 的 contextlib.ExitStack的現有實用程序可以關閉分配的資源? 我希望它看起來像這樣:
try (ExitStack exitStack = new ExitStack()) {
List<Widget> widgets = new ArrayList<>();
for (...) {
widgets.add(exitStack.add(new Widget()));
}
// use widgets
}
(注意:這不是這個問題,因為我不知道我會提前擁有多少資源。
嘿親密的選民,我不是要圖書館,我是問你如何完成安全關閉動態數量的AutoCloseable
的任務,如果有語言功能,很好,如果有標准庫功能,還有太好了,如果我必須自己寫,那很好。 如果您想推薦的是,在它的話,當然有這個共同使用一個第三方庫。
鑒於此實用程序似乎不存在,我寫了一個。 它包含任何拋出的異常,然后僅在資源的 close() 拋出時拋出。 在返回之前總是關閉所有東西。
public class ClosingException extends Exception { }
和
import java.util.Deque;
import java.util.ArrayDeque;
public final class ClosingStack implements AutoCloseable {
public void close() throws ClosingException {
ClosingException allClosingExceptions = new ClosingException();
while (!resources.isEmpty()) {
try {
resources.removeLast().close();
} catch (Throwable e) {
allClosingExceptions.addSuppressed(e);
}
}
if (allClosingExceptions.getSuppressed().length != 0) {
throw allClosingExceptions;
}
}
public <T extends AutoCloseable> T add(T resource) {
resources.addLast(resource);
return resource;
}
private Deque<AutoCloseable> resources = new ArrayDeque<>();
}
並使用:
try (ClosingStack closingStack = new ClosingStack()) {
List<Widget> widgets = new ArrayList<>();
for (...) {
widgets.add(closingStack.add(new Widget()));
}
// use widgets
}
我想你會發現 Guava 的Closer
課程正是你所需要的:
try (Closer closer = Closer.create()) {
InputStream in1 = closer.register(new FileInputStream("foo"));
InputStream in2 = closer.register(new FileInputStream("bar"));
// use in1 and in2
}
// in2 and in1 closed in that order
請注意,該課程仍被標記為 Beta,但似乎一直存在。 最初的目的是在沒有 Java 7 語言特性支持的情況下提供一種嘗試資源的體驗,但是一個有用的副作用是它應該使用動態數量的資源。
也許你可以這樣做:
<T extends AutoCloseable> void recursively(
List<T> things,
Iterator<? extends Supplier<? extends T>> thingSuppliers,
Consumer<List<T>> whenEmpty) {
if (!thingSuppliers.hasNext()) {
// No more to create. Pass all the things to the consumer.
whenEmpty.accept(things);
return;
}
// Create a new thing, and make a recursive call. This thing gets
// closed as the stack unwinds.
try (T thing = thingSuppliers.next().get()) {
things.add(thing);
recursively(things, thingSuppliers, whenEmpty);
}
}
// Some means of starting the recursion.
<T extends AutoCloseable> void recursively(
Iterable<? extends Supplier<? extends T>> thingSuppliers,
Consumer<List<T>> whenEmpty) {
recursively(new ArrayList<>(), thingSuppliers.iterator(), whenEmpty);
}
示例調用:
recursively(
Arrays.asList(Widget::new, Widget::new),
System.out::println);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.