可索引集合的抽象迭代器

时间:2012-11-23 19:50:16

标签: java indexing iterator abstract-class

我的框架充满了像

这样的迭代器
int n = col.getSize();
for (int i = 0 ; i != n; i++) {
  Type obj = col.get(i);

并且,我觉得每个在索引上迭代项目的程序都有一段这样的代码。与整洁的foreach相比,感觉很丑陋

for (Type obj : col) {

转换到foreach需要使所有集合都可以进行,这意味着在每个iterator()方法中创建一个新的迭代器。现在,我在每个集合声明中都有丑陋的代码而不是它的使用位置。所以,我做得很好,我把丑陋的代码移到了common.utils中。

public abstract class ImmutableIterator<T> implements Iterator<T> {
    private int i = 0; 
    private final int size = getSize();

    public abstract int getSize();  // to be implemented by user
    public abstract T getValue(int i); // to be implemented by user

    public T next() { 
        if (!hasNext()) throw new NoSuchElementException(); 
        return getValue(i++);
    }

    public boolean hasNext() { return i != size;}

    public void remove() {
        throw new UnsupportedOperationException("Remove is not implemented");
    }
}

现在,我已经将这个丑陋的图案隔离开了。这是我能做的最好的事情。集合将提供大小和价值(i)。唯一的问题是性能penaly:我必须在循环中进行两次大小检查,首先是hasNext,另一个是next()。我想知道为什么Sun不提供这样的课程?每个人都需要它。我只是忽略了它吗?

2 个答案:

答案 0 :(得分:1)

在抽象类中共享的代码很少,因此抽象几乎没有带来任何好处。我认为在每个集合中从头开始实现这样的迭代器同样容易。在许多情况下,hasNext可能更直接地实现,例如。

请注意,您的抽象类具有与非抽象代码行一样多的抽象行。现在,许多类可能想要实现可变迭代器,然后在抽象类中几乎没有任何东西。

另外,永远不需要改变。如果允许您进行一次错误修改等更改并同时修复多个类,则抽象类特别好。但是,这段代码很简单,这个bug会是什么?例如,“删除”中的“抛出”几乎没有错误 - 它永远不应该被执行。在多个迭代器中共享它没有任何好处。

答案 1 :(得分:0)

Tomasz Nurkiewicz将我们带到了番石榴的UnmodifiableIterator。但是,这里只定义了remove方法,而我们也想要索引迭代。这个提示让LouisWasserman找到了更好的解决方案:AbstractIndexedListIterator做了我们想要的。唯一的缺点是这个类没有实现remove方法,而是在Guava包中关闭。所有这些告诉我们这些类非常有用,但必须由用户在他的框架中实现。

JB Nizet提出了另一种解决方案。我们可以返回从底层集合中重新获取的一个迭代器接口,而不是在getSize / GetItem(idx)方法之上实现迭代器接口。