Closing a java.util.Iterator

Viewed 23408

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

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 before the last iteration as it is shown in my example.

7 Answers

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

Example:

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

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.

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.

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

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

For example

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

An Implementation of it:` public class MyIteratorImpl implements 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:

` public class 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;
}

} `

Related