簡體   English   中英

在 try-with-resources 中關閉動態數量的 AutoCloseable 對象

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM