Java中是否有传统的迭代器接口将遍历与元素访问分开?

时间:2015-06-13 20:44:54

标签: java iterator

对于我的应用程序,元素访问很昂贵,所以java.util.Iterator没用。我想要更像C ++迭代器的东西,我可以在不返回元素的情况下移动指针。这样的标准库中有什么东西,或者是否有通过自定义演变的事实上的标准接口? (如果没有,请不要浪费时间发布代码片段 - 我完全能够想出合理的名字来完成这项工作)。

2 个答案:

答案 0 :(得分:2)

java.util.Iterator是一个接口,而不是一个实现。迭代器的行为取决于您使用的集合以及如何获取它。

大多数人不应该做任何昂贵的事情,因为对于Objects,Java传递他们的引用。无论您访问的是什么,都是昂贵的,应该在一个Object之后抽象出来,允许您在不试图访问它的情况下引用它。

如果您的抱怨与界面相关并且需要其他方法,那么您需要自己提出并遵循该界面; java.util.Iterator Java的传统迭代器,部分原因可能是我提到过。

答案 1 :(得分:0)

(由于没有人来写一个正确的答案,我会将我的评论扩展为答案。)

据我所知,标准API中没有适合您的界面(即iterator.skip()之类的界面)。我认为,使用标准API方法的最佳解决方案是yourList.sublist(startIndex).iterator()

我认为,如果可能的话,您应该考虑创建自己的迭代器接口。 (注意,如果需要,可以让它扩展java.util.Iterator接口,以便能够将它用作普通迭代器。)

最后,这主要是为了让未来的读者 使用java.util.Iterator 来懒惰地访问基础列表,您可以使用{{ 3}}。请注意,Proxy对象并不能始终与序列化/持久性库一起使用,并且它要求您使用接口。一个例子如下:

这是 OnDiskList,在每次get(int n)的调用中取 n 行:

class OnDiskList extends AbstractList<CharSequence> {

    // Slow list access method: Linear search for n:th line.
    @Override
    public CharSequence get(int n) {
        System.out.println("Fetching line " + n + "...");
        try (Stream<String> lines = Files.lines(Paths.get("big-file.txt"))) {
            return lines.skip(n).findFirst().get();
        } catch (IOException shouldBeHandled) {
            return null;
        }
    }

    @Override
    public int size() {
        return 5;
    }
}

以下是使用普通迭代器时输出的外观:

Iterator<CharSequence> normalIter = onDiskList.iterator();
normalIter.next(); // Skip
normalIter.next(); // Skip
normalIter.next(); // Skip
System.out.println(normalIter.next()); // Print

<强>输出:

Fetching line 0...
Fetching line 1...
Fetching line 2...
Fetching line 3...
Line 3 in big-file.txt

现在到了魔法:这里有一个ProxyingIterator隐藏了Proxy后面的对象,它懒洋洋地访问列表:

class ProxyingIterator implements Iterator<CharSequence> {

    List<CharSequence> slowList;
    int pos = 0;

    public ProxyingIterator(List<CharSequence> slowList) {
        this.slowList = slowList;
    }

    @Override
    public boolean hasNext() {
        return pos < slowList.size();
    }

    @Override
    public CharSequence next() {
        return (CharSequence) Proxy.newProxyInstance(
                        CharSequence.class.getClassLoader(),
                        new Class[] { CharSequence.class },
                        new LazyLoadingInvocationHandler(pos++));
    }

    private class LazyLoadingInvocationHandler implements InvocationHandler {

        int index;
        CharSequence loadedObject = null;

        public LazyLoadingInvocationHandler(int index) {
            this.index = index;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) {
            if (loadedObject == null)
                loadedObject = slowList.get(index);
            try {
                return method.invoke(loadedObject, args);
            } catch (Exception shouldNotHappen) {
                shouldNotHappen.printStackTrace();
                return null;
            }
        }
    }
}

使用此迭代器时,它看起来如下:

Iterator<CharSequence> proxyingIter = new ProxyingIterator(onDiskList);
proxyingIter.next(); // Skip
proxyingIter.next(); // Skip
proxyingIter.next(); // Skip
System.out.println(proxyingIter.next()); // Print

<强>输出:

Fetching line 3...
Line 3 in big-file.txt