How to create a Java iterator that throws an IOException

I would like to implement an iterator that retrieves objects from a disk / network.

Iterator itr = getRemoteIterator(); while(itr.hasNext()) { Object element = itr.next(); System.out.print(element + " "); } 

However, the problem is that the hasNext() and next() methods of the Iterator object do not allow an IOException to be thrown. Is there any other standard interface around this problem?

Required Code:

 public interface RemoteIterator<E> { boolean hasNext() throws IOException; E next() throws IOException; void remove(); } 
+8
java iterator java-7 ioexception
source share
11 answers

This is not exactly what you want, but think:

This happens over the network, so it can be slow. You should probably use Future (or the like).

So instead of RemoteIterator<E> , where next() returns E, use

RemoteIterator<Future<E>> , where it returns Future<E> .

In the Future.get() method, you can wrap any IOException in an ExecutionException .

Not perfect, but Future.get() implies that everything can be slow, plus it throws a checked exception, which will tell other programmers what is happening, and the natural answer is to call getCause() . Thus, this avoids most aspects of the โ€œWTFโ€.

+6
source share

Unfortunately, you cannot do this. Exclusions are part of the method signature, and although you can narrow them down, for example.

 interface FooCallable extends Callable<T> { T call() throws IOException; // Narrows Exception from the parent interface } 

you cannot enter new throw offers or extend the declared one.

Iterator is the fundamental Java interface used by advanced for, so even if you can somehow do what you need, the compiler needs to know that

 for (T obj: ioExceptionThrowingIterable) { ... } 

it is required that a validated IOException be caught or thrown.

This is a matter of opinion, but I think you should use your own RuntimeException subclass and carefully document your interface. Verified exceptions are excluded in the modern framework, for example. Spring, due to problems associated with them.

Edit : borrowed and adapted from user949300 answer, you can wrap the returned object, for example,

 interface RemoteObject<T> { T get() throws IOException } 

Then return Iterator<RemoteObject<T>> and force the caller to handle the IOException when deploying with get :

 for (RemoteObject<Foo> obj: iterable) { try { foo = obj.get() } catch (IOException ex) { /* * 9 times out of 10, the lazy user just prints the stack trace * or something else inappropriate * which is why I despise checked exceptions */ } } 

In this case, there is no need to extend Iterator , it can be used directly. In fact, you can use Collection , if applicable.

+6
source share

Next () throws http://docs.oracle.com/javase/7/docs/api/java/util/NoSuchElementException.html . You can write your own exception class, catch this exception, and then throw an IOException.

+3
source share

I would prefer that the getRemoteIterator () method should ideally throw an IOException, as objects will be searched inside the method.

+1
source share

Iterator is a well-designed design template . If the Iterator SDK does not meet your current needs, you can make an iterator yourself.

I find a good explanation and sample code on this site . You can take this code as a reference and run your own implementation of the Iterator interface.

+1
source share

The main problem is that you want to be able to throw a checked exception through an API that is not intended for this.

The only legal way to get this to work without black magic is to wrap it with unchecked exceptions. The simplest is a RuntimeException:

 } catch (IOException e) { throw new RuntimeException("failed in " + fileName, e); } 

Then you can catch a RuntimeException in the calling code and look at the getCause() method.

If you need to explicitly say that this is your exception, consider creating a FooBarDomainException extends RuntimeException and run the constructors you need to delegate to super(...,e) . You can then catch a FooBarException and handle getCause() as above.

I advise you not to use magic for this. When magic breaks down, it has very unobvious ways that are hard to find and fix. In addition, it will be difficult for others to support.

+1
source share

Here is my contribution and the bottom of the stack.

This is not exactly what you want, but close by.

 public class IOIterator<E> implements Iterator<E> { @Override public boolean hasNext() { return index < 5; } @Override public E next() { try { if( index++ > 3) { throw new IOException( "True fault origin" ); } } catch( Throwable t ) { NoSuchElementException nse = new NoSuchElementException( "index: " + index ); nse.initCause( t ); throw nse; } return null; } @Override public void remove() { if( index == 0 ) throw new IllegalStateException( "call next first!" ); try { if( index == 4 ) { throw new IOException( "True fault origin" ); } } catch( Throwable t ) { UnsupportedOperationException uoe = new UnsupportedOperationException( "index: " + index ); uoe.initCause( t ); throw uoe; } } private int index; public static void main( String[] args ) { IOIterator<Socket> it = new IOIterator<>(); while( it.hasNext()) { Socket socket = it.next(); } } } 

And the exception stack trace:

 Exception in thread "main" java.util.NoSuchElementException: index: 5 at hpms.study.IOIterator.next(IOIterator.java:32) at hpms.study.IOIterator.main(IOIterator.java:67) Caused by: java.io.IOException: True fault origin at hpms.study.IOIterator.next(IOIterator.java:27) ... 1 more 
+1
source share

I suggest creating your own interface, which is structurally similar to Iterator, but has the additional interface limitation that you wanted.

It looks like you actually have Stream of objects. I would go along this route, the attendant expectation is that sometimes you will get an EOFException or the like.

0
source share

There is another approach to this problem. The main idea is to extend NoSuchElementException :

 class RemoteIOException extends NoSuchElementException { ... } 

The downside is that NoSuchElementException extends RuntimeException .

0
source share

checked exception is just a syntax limit

The code below is from lombok http://www.projectlombok.org/

You'll get

Exception in thread "main" java.io.IOException on B.main (B.java:19)

 public static RuntimeException sneakyThrow(Throwable t) { if (t == null) throw new NullPointerException("t"); B.<RuntimeException>sneakyThrow0(t); return null; } @SuppressWarnings("unchecked") private static <T extends Throwable> void sneakyThrow0(Throwable t) throws T { throw (T)t; } public static void main(String[] args) { throw sneakyThrow(new IOException()); } 
-one
source share

I posted a few ideone code examples . The basic idea is to create a custom RuntimeException IOIteratorException class that IOIteratorException IOException. Then you can write such code

 try { iterator . next ( ) ; } catch ( IOIteratorException cause ) { cause . getCause ( ) ; // the compiler knows this is an IOException so you don't need to cast it } 
-one
source share

All Articles