关闭java.util.Iterator

Pie*_*rre 32 java resources iterator

我已经 使用应该使用方法在最后发布的资源实现了自定义java.util.Iteratorclose().该资源可以是java.sql.ResultSet,java.io.InputStream等...

public interface CloseableIterator<T> extends Iterator<T>
  {
  public void close();
  }
Run Code Online (Sandbox Code Playgroud)

使用此迭代器的某些外部库可能不知道必须关闭它.例如:

public boolean isEmpty(Iterable<T> myiterable)
 {
 return myiterable.iterator().hasNext();
 }
Run Code Online (Sandbox Code Playgroud)

在那种情况下,有没有办法关闭这个迭代器?

更新:非常感谢您当前的答案.我会给每个人一个(+1).当hasNext()返回false 时,我已经关闭了Iterator .我的问题是当循环迭代最后一次迭代之前中断时,如我的例子中所示.

Nic*_*rot 21

创建一个实现AutoCloseable接口的自定义迭代器

public interface CloseableIterator<T> extends Iterator<T>, AutoCloseable {
}
Run Code Online (Sandbox Code Playgroud)

然后在try with resource语句中使用此迭代器.

try(CloseableIterator iterator = dao.findAll()) {
    while(iterator.hasNext()){
       process(iterator.next());
    }
}
Run Code Online (Sandbox Code Playgroud)

无论发生什么情况,这种模式都将关闭底层资源: - 语句完成后 - 即使抛出异常

最后,清楚地记录必须如何使用此迭代器.

如果您不想委派关闭呼叫,请使用推送策略.例如.用java 8 lambda:

dao.findAll(r -> process(r));
Run Code Online (Sandbox Code Playgroud)

  • 到目前为止,这是最好的解决方案。还可以重写close方法并删除throws子句,以避免必须为每种try-with-resources用法添加catch子句。 (2认同)

Osc*_*Ryz 14

在你的实现中,如果迭代器耗尽,你可以将它自己关闭.

public boolean hasNext() {
       .... 
       if( !hasNext ) {
           this.close();
       }
       return hasNext;
 }
Run Code Online (Sandbox Code Playgroud)

并清楚地记录:

当hasNext()返回false时,此迭代器将调用close(),如果您需要先处置迭代器,请确保调用close close your self

例:

void testIt() {
     Iterator i = DbIterator.connect("db.config.info.here");
     try {
          while( i.hasNext() {
              process( i.next() );
          }
      } finally {
          if( i != null )  {
              i.close();
          }
      }
  }
Run Code Online (Sandbox Code Playgroud)

顺便说一句,你可以在那里实现Iterable并使用增强的for循环.


And*_*s_D 9

问题是最后的情况.我们经常迭代完整的集合或数据集,所以我们现在已经到了最后,没有数据可供阅读.

但是如果我们在到达数据结束之前设置了循环中断,则迭代器将不会结束并且不会被关闭.

一种出路可能是在构造期间将数据源的内容缓存在迭代器中并关闭资源.因此迭代器不会对打开的资源起作用,而是对缓存的数据起作用.

  • 确实有效,但可能不是非常高效的内存,或者缓存可能会成为一个非常繁重的操作. (2认同)

NG.*_*NG. 7

你可以在终结器中关闭它,但它不会给你你想要的行为.只有当垃圾收集器想要清理对象时才会调用终结器,因此您的资源可能会保持打开状态.更糟糕的是,如果有人抓住你的迭代器,它永远不会关闭.

有可能在第一次调用hasNext()时关闭流,返回false.由于有人可能只迭代第一个元素并且再也不打扰它,所以仍然无法保证这样做.

真的,我认为在处理外部库时你需要自己管理它.您将对使用iterable的方法进行调用,那么为什么不在完成后自行关闭它?资源管理不是你可以强加给不了解更好的外部库的东西.


sma*_*c89 5

如果可能,将迭代器包装在 Stream 中,这样您就可以访问onClose流的方法。然后您应该将关闭逻辑移至该方法中并在那里进行清理。

例子:

StreamSupport.stream(Spliterators.spliteratorUnknownSize(
        new MyCustomIterator<T>(), 0), false).onClose(() -> {
    // close logic here
});
Run Code Online (Sandbox Code Playgroud)