在try-with-resources中关闭动态数量的AutoCloseable对象

时间:2019-04-26 16:40:25

标签: java java-8 try-with-resources autocloseable

我正在try-with-resources块中创建可变数量的try (ExitStack exitStack = new ExitStack()) { List<Widget> widgets = new ArrayList<>(); for (...) { widgets.add(exitStack.add(new Widget())); } // use widgets } 对象。在任何出口,我都希望所有分配的资源都关闭。

我可以想象自己写点东西来做到这一点,但是是否存在类似于Python's contextlib.ExitStack的现有实用程序将关闭分配的资源?我希望它看起来像这样:

AutoCloseable

(注意:这不是this question,因为我不知道我会提前拥有多少资源。

嘿,亲密的选民,我不是要图书馆,而是要问您如何完成安全sub $t0,$s3,$s4 add $t0,$s6,$t0 lw $t1,16($t0) sw $t1,32($s7) 个动态关闭的任务(如果有语言)它的功能很棒,如果有标准的库函数,也很棒,如果我必须自己编写的话,也很好。如果您想喜欢推荐一个常用的第三方库,请确保该库。

3 个答案:

答案 0 :(得分:1)

鉴于此实用程序似乎不存在,我写了一个。它包装所有抛出的异常,然后仅在抛出资源的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
}

答案 1 :(得分:1)

我想您会在这里找到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语言功能支持的情况下提供尝试资源的体验,但是一个有用的副作用是它应该使用动态数量的资源。

答案 2 :(得分:0)

也许您可以执行以下操作:

<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);