views:

62

answers:

3

Hi all, I've implemented a custom java.util.Iterator using a resource that sould 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 ?

Many Thanks,

Pierre

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.

+4  A: 

You could close it in a finalizer but 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.

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.

SB
+2  A: 

The problem is the condition at the end. Often we iterate over a full collection or data set, so we're at the end at 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.

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.

Andreas_D
+2  A: 

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

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.

OscarRyz