如何创建抛出IOException的Java Iterator

Ant*_*nio 8 java iterator ioexception java-7

我想实现一个从磁盘/网络中检索对象的迭代器.

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

然而问题是,hasNext()next()该方法的迭代器对象不允许扔IOException.是否还有其他标准接口可以解决此问题?

期望的代码是:

public interface RemoteIterator<E> {
    boolean hasNext() throws IOException;
    E next() throws IOException;
    void remove();
}
Run Code Online (Sandbox Code Playgroud)

art*_*tol 6

不幸的是你不能这样做.声明的异常是方法签名的一部分,而你可以缩小范围,例如

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

你不能引入新的throws子句或扩大声明的子句.

Iterator 是一个基本的Java接口,由增强版使用,所以即使你能以某种方式做你想做的事情,编译器也需要知道

for (T obj: ioExceptionThrowingIterable) { ... }
Run Code Online (Sandbox Code Playgroud)

要求检查IOException被抓住或抛出.

这是意见问题,但我认为您应该使用自定义子类RuntimeException并仔细记录您的界面.在现代框架中避免了检查异常,例如Spring,因为它们存在相关问题.

编辑:借用并改编自user949300的答案,您可以将返回的对象包装在例如

interface RemoteObject<T> {
    T get() throws IOException
}
Run Code Online (Sandbox Code Playgroud)

然后返回一个Iterator<RemoteObject<T>>,并强制调用者处理打开IOExceptionget:

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
     */
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,没有必要扩展Iterator,它可以直接使用.事实上,Collection如果适用,您可以使用.


use*_*300 6

这不完全是你想要的,但考虑:

这是通过网络发生的,因此可能很慢.你可能应该使用Future (或类似的).

所以,不要让你的RemoteIterator<E>位置next()返回E,而是使用

RemoteIterator<Future<E>>,它返回一个Future<E>.

在该Future.get()方法中,您可以将任何内容包装IOException在中ExecutionException.

不完美,但Future.get()暗示事情可能会很慢,而且它会抛出一个检查异常,这将使其他程序员发现正在发生的事情,并且自然的响应是调用getCause().因此,这避免了大多数"WTF"方面.