关闭 java.util.Iterator

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3257972/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 01:02:11  来源:igfitidea点击:

Closing a java.util.Iterator

javaresourcesiterator

提问by Pierre

I've implemented a custom java.util.Iteratorusing a resource that should be released at the end using a close()method. That resource could be a java.sql.ResultSet, a java.io.InputStreametc...

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

public interface CloseableIterator<T> extends Iterator<T>
  {
  public void close();
  }

Some external libraries using this iterator might not know that it must be closed. e.g:

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

public boolean isEmpty(Iterable<T> myiterable)
 {
 return myiterable.iterator().hasNext();
 }

In that case, is there a way to close this iterator?

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

Update:many thanks for the current answers . I'll give a (+1) to everybody. I do already close the Iterator when hasNext()returns false. My problem is when the loop iterating breaks beforethe last iteration as it is shown in my example.

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

采纳答案by Andreas Dolk

The problem is the condition at the end. Often we iterate over a full collection or data set, so we're at the endat the moment, there's no data left to read.

问题是条件。我们经常迭代一个完整的集合或数据集,所以我们现在处于最后,没有数据可以读取。

But if we set a break out of the loop before we reached the End Of Data, the iterator wouldn't come to an end and wouldn't be closed.

但是,如果我们在到达 End Of Data 之前设置了循环的中断,则迭代器不会结束也不会关闭。

A way out could be to cache the content of the data source in the iterator during construction and close the resource. So the iterator would not work on the opened resource but on cached data.

一个出路可能是在构建期间在迭代器中缓存数据源的内容并关闭资源。所以迭代器不会在打开的资源上工作,而是在缓存的数据上工作。

回答by Nicolas Labrot

Create a custom iterator which implement the AutoCloseable interface

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

public interface CloseableIterator<T> extends Iterator<T>, AutoCloseable {
}

And then use this iterator in a try with resource statement.

然后在try with resource 语句中使用这个迭代器。

try(CloseableIterator iterator = dao.findAll()) {
    while(iterator.hasNext()){
       process(iterator.next());
    }
}

This pattern will close the underlying resource whatever happens: - after the statement complete - and even if an exception is thrown

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

Finally, clearly document how this iterator must be used.

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

If you do not want to delegate the close calls, use a push strategy. eg. with java 8 lambda:

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

dao.findAll(r -> process(r));

回答by OscarRyz

In your implementation you could close it your self, if when the iteratoror is exhausted.

在您的实现中,如果迭代器耗尽,您可以自行关闭它。

public boolean hasNext() {
       .... 
       if( !hasNext ) {
           this.close();
       }
       return hasNext;
 }

And clearly document:

并清楚地记录:

This iterator will invoke close() when hasNext() return false, if you need to dispose the iterator before make sure you call close your self

当 hasNext() 返回 false 时,此迭代器将调用 close(),如果您需要在确保调用 close 您的 self 之前处置迭代器

example:

例子:

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

Btw, you could while you're there you could implement Iterable and use the enhanced for loop.

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

回答by NG.

You could close it in a finalizerbut it's not going to give you the behavior you want. Your finalizer is called only when the garbage collector wants to cleanup your object, so your resource might remain open. Worse, if someone holds onto your iterator, it'll never close.

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

There's a possibility of closing the stream on the first call to hasNext() that returns false. That's still not guaranteed to do it since someone might iterate only the first element and never bother with it again.

有可能在第一次调用 hasNext() 返回 false 时关闭流。这仍然不能保证这样做,因为有人可能只迭代第一个元素并且再也不会打扰它。

Really, I think you'll need to manage it yourself when dealing with an external library. You're going to make those calls to the methods that use the iterable, so why not close it yourself when you're done? Resource management is not something you can just impose on an external library that doesn't know any better.

真的,我认为在处理外部库时您需要自己管理它。您将要对使用可迭代对象的方法进行这些调用,那么为什么在完成后不自己关闭它呢?资源管理不是你可以强加给一个不知道更好的外部库的东西。

回答by Jesse Barnum

Just define your own sub-interface of Iterator that includes a close method, and make sure you use that instead of the regular Iterator class. For example, create this interface:

只需定义包含 close 方法的 Iterator 子接口,并确保使用它而不是常规 Iterator 类。例如,创建这个接口:

import java.io.Closeable;
import java.util.Iterator;

public interface CloseableIterator<T> extends Iterator<T>, Closeable {}

And then an implementation might look like this:

然后一个实现可能看起来像这样:

List<String> someList = Arrays.asList( "what","ever" );
final Iterator<String> delegate = someList.iterator();
return new CloseableIterator<String>() {
    public void close() throws IOException {
        //Do something special here, where you have easy
        //access to the vars that created the iterator
    }

    public boolean hasNext() {
        return delegate.hasNext();
    }

    public String next() {
        return delegate.next();
    }

    public void remove() {
        delegate.remove();
    }
};

回答by Eurospoofer

I had a similar issue in one of my projects using an Iterator like an Object stream. To cover the times the Iterator is not fully consumed, I also needed a close method. Initially I simply extended Iterator and Closable interfaces, but digging a little deeper, the try-with-resources statement introduced in java 1.7, I thought provided a tidy way of implementing it.

我在使用像对象流这样的迭代器的一个项目中遇到了类似的问题。为了覆盖 Iterator 未完全消耗的时间,我还需要一个 close 方法。最初我只是简单地扩展了 Iterator 和 Closable 接口,但深入挖掘了一下,java 1.7 中引入的 try-with-resources 语句,我认为提供了一种简洁的实现方式。

You extend Iterator and AutoCloseable interfaces, implement the Close method and use the Iterator in a try-with-resources. The Runtime will call close for you once the Iterator is out of scope.

您可以扩展 Iterator 和 AutoCloseable 接口,实现 Close 方法并在 try-with-resources 中使用 Iterator。一旦迭代器超出范围,运行时将为您调用 close。

https://docs.oracle.com/javase/7/docs/api/java/lang/AutoCloseable.html

https://docs.oracle.com/javase/7/docs/api/java/lang/Au​​toCloseable.html

https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

For example

例如

The Interface:public interface MyIterator<E> extends Iterator<E>, AutoCloseable { }

界面:public interface MyIterator<E> extends Iterator<E>, AutoCloseable { }

An Implementation of it:` public class MyIteratorImpl implements MyIterator {

它的一个实现:` public class MyIteratorImpl 实现 MyIterator {

private E nextItem = null;

@Override
public boolean hasNext() {
    if (null == nextItem)
        nextItem = getNextItem();

    return null != nextItem;
}

@Override
public E next() {
    E next = hasNext() ? nextItem : null;
    nextItem = null;
    return next;
}

@Override
public void close() throws Exception {
    // Close off all your resources here, Runtime will call this once 
       Iterator out of scope.
}

private E getNextItem() {
    // parse / read the next item from the under laying source.
    return null;
}

} `

}`

And an example of using it with the try -with-resource:

以及将它与 try -with-resource 一起使用的示例:

` public class MyIteratorConsumer {

` 公共类 MyIteratorConsumer {

/**
 * Simple example of searching the Iterator until a string starting 
 *  with the given string is found.
 * Once found, the loop stops, leaving the Iterator partially consumed.
 * As 'stringIterator' falls out of scope, the runtime will call the 
 * close method on the Iterator.
 * @param search the beginning of a string
 * @return The first string found that begins with the search
 * @throws Exception 
 */
public String getTestString(String search) throws Exception {
    String foundString = null;

    try (MyIterator<String> stringIterator = new MyIteratorImpl<>()) {
        while (stringIterator.hasNext()) {
            String item = stringIterator.next();
            if (item.startsWith(search)) {
                foundString = item;
                break;
            }
        }

    }
    return foundString;
}

} `

}`

回答by smac89

If possible, wrap the iterator in a Stream, which will give you access to the onClosemethod of streams. Then you should move your close logic into that method and do your cleanup there.

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

Example:

例子:

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