tags:

views:

344

answers:

5

In java a class can implement Iterable which lets you use the foreach() statement and the iteration syntatic sugar:

for(T t:ts) ...

However, this does not allow you to throw exceptions on the construction for an Iterator. If you were iterating off a network, file, database etc it would be nice to be able to throw exceptions. Obvious candidates are java.io.InputStream, Reader and the java.nio.Channel code, but none of this can use Generics like the Iterable interface can.

Is there a common idiom or Java API for this situation?

Clarification: This is asking if there is a pattern or alternative interface for iterating for objects off a non-memory source. As responders have said, just throwing RuntimeExceptions to get around the problem is not recommended or what I was looking for.

Edit 2: Thanks to answers so far. The consensus seems to be "you can't". So can I extend the question to "What do you do in this situation, when this situation would be useful?" Just write your own interface?

A: 

I'd say you can't, even if you could you probably shouldn't. You get bytes from these things, if they were used in a for loop likely every byte would end up boxed.

What you can do is wrap checked exceptions in unchecked exceptions and comply to the iterable interface, though again this isn't advisable.

Tom
+4  A: 

Streams like a network aren't really iterable in the traditional sense. Data can come through at any time, so it doesn't make sense to have a for each loop.

For a file read, or a DB snapshot (like a select query) there's no reason you can't take that data, segment it into logical chunks and implement an iterable interface.

You can also call an initialize method first that will catch any exceptions, if that's an issue.

try{
   ts.initializeIOIterator();
}catch(...)

for(T t:ts)
...
patros
Thanks for the answer. But if you call initialise first you have to read everything into memory first, and lose the benefit of streaming, or you have to cope with exceptions
Nick Fortescue
Yup. You pretty much have to choose one metaphor or the other. If you're dealing with a true stream, then you're better off sticking with the stream metaphor.
patros
+2  A: 

Unfortunately you can't. There are two problems:

  • The Iterator API doesn't declare any exceptions to be thrown, so you'd have to throw RuntimeExceptions (or non-Exception throwables)
  • The enhanced for loop doesn't do anything to try to release resources at the end of the loop

This is very annoying. In C#, for instance, you can really easily write code to iterate through the lines of a text file:

public static IEnumerable<string> ReadLines(string filename)
{
    using (TextReader reader = File.OpenText(filename))
    {
        string line;
        while ( (line=reader.ReadLine()) != null)
        {
            yield return line;
        }
    }
}

Use as:

foreach (string line in ReadLines("foo.txt"))

The foreach loop calls Dispose on the IEnumerator in a finally block, which translates to "check if we need to do anything in the iterator block's finally (from the using statement)". Obviously there are no checked exceptions in C#, so that side of things isn't a problem either.

A whole (useful!) idiom is pretty much unworkable in Java due to this.

Jon Skeet
+1  A: 

Best what you can do is to create RuntimeIOException which you will throw from your hasNext/next implementation in case of errors.

try {
  for (...) {
    // do my stuff here
  }
catch (RuntimeIOException e) {
  throw e.getCause(); // rethrow IOException
}

RuntimeIOException will be runtime exception, wrapping your IOException:

class RuntimeIOException extends RuntimeException {
  RuntimeIOException(IOException e) {
    super(e);
  }

  IOException getCause() {
    return (IOException) super.getCause();
  }
}

Sometimes there is no other way.

Peter Štibraný
A: 

Generally in this situation, I would throw an appropriate subclass of RuntimeException in the Iterable's implementation.

In terms of cleaning up resources, a try - finally block works just as well wrapping a foreach block as it does around any other bit of code, so from the client's perspective it can easily use this to clean up any resources. If you want to manage resources within the Iterable it can be trickier, since there's no obvious start and finish lifecycle points.

In this case the best you could probably do is to create the resources on demand (i.e. the first call to next()), and then destroy them either when a call to next() is about to return false, or when an exception is thrown in the body of next(). Doing this would of course mean that when your next() method exits with an exception, the iterator can no longer be used - this is not an unreasonable constraint to place (consider the exception a more error-y version of returning false) but is something you should document as this isn't strictly covered by the interface.

That said, the above assumes that you're creating something solely as an Iterable. I find that in practice, when I implement Iterable on a class, it's more like a "super-getter" (i.e. a way for clients to conveniently access the information stored within it), than it is the point of the class itself. Most of the time these objects will be set up independently and accessed via other methods, so their lifecycle can be managed completely separately from their existence as an Iterable.

This might seem tangential to the question, but the immediate answer to the question is straightforward ("use runtime exceptions") - the tricky part is maintaining an appropriate state in the presence of these exceptions.

Andrzej Doyle