Java:为什么迭代器不可复制

Java:为什么迭代器不可复制,java,iterator,copy,iterable,Java,Iterator,Copy,Iterable,我认为,Iterator.copy()将是一个非常方便的函数。您可以用更好的方式实现迭代器过滤器 例如,在Google Java集合中,filter(以及类似的)函数使用UnmodifiableIterator(它只是一个没有remove)的迭代器)的唯一原因是,您无法实现这样的过滤器迭代器,否则您就无法在某个时刻复制它。(实际上,在当前界面上不可能做到这一点;请自己尝试。) 另一个优点是,您可以在for-each循环中使用迭代器:因为可复制迭代器也将自动可iterable。另见问题。现在,不允

我认为,
Iterator.copy()
将是一个非常方便的函数。您可以用更好的方式实现迭代器过滤器

例如,在Google Java集合中,
filter
(以及类似的)函数使用
UnmodifiableIterator
(它只是一个没有
remove
)的
迭代器
)的唯一原因是,您无法实现这样的过滤器
迭代器,否则您就无法在某个时刻复制它。(实际上,在当前界面上不可能做到这一点;请自己尝试。)

另一个优点是,您可以在for-each循环中使用迭代器:因为可复制迭代器也将自动可iterable。另见问题。现在,不允许这样做的主要设计原因是,实现
Iterable
Iterator Iterator(){return this;}
迭代器将使迭代器无效。通过使用
copy
函数,它与
Iterator Iterator(){return copy();}
一样简单,并且不会使原始迭代器无效。因此,没有理由再不允许这样做了


有什么原因吗?只是为了降低实现的复杂性?

尽管迭代器通常是这样,但理论上不必将迭代器链接到集合。例如,输入流上的复制方法将很难实现,并且很容易导致模糊的内存问题

有什么原因吗?只是为了让它实现起来不那么复杂


设计和实现一个支持
copy
操作的
迭代器
包装类将非常简单。不过,我不确定它是否会普遍有用,尤其是因为在一般情况下,这将是一项昂贵的手术。仅此一点就足以让Java设计人员不想将
copy()
添加到
Iterator
接口

跟进

这就是我想到的事情:

public class CopyableIterator<T> implements Iterator<T> {
    private Iterator<T> it;
    private List<T> copy = new ArrayList<T>();
    private int pos;
    public CopyableIterator(Iterator<T> it) {
        while (it.hasNext()) {
            copy.append(it.next());
        }
        this.it = copy.iterator();
    }
    public T next() {
        T res = next();
        pos++;
        return res;
    }
    public boolean hasNext() {
        return it.hasNext();
    }
    public Iterator<T> copy() {
        return copy.sublist(pos, copy.size()).iterator();
    }
    public void remove() {
        throw new UnsupportedOperationException();
    }
}
公共类CopyableIterator实现迭代器{
私有迭代器;
私有列表副本=新建ArrayList();
私人国际邮政局;
公共CopyableIterator(Iterator it){
while(it.hasNext()){
copy.append(it.next());
}
this.it=copy.iterator();
}
公共交通工具{
T res=next();
pos++;
返回res;
}
公共布尔hasNext(){
返回它。hasNext();
}
公共迭代器副本(){
返回copy.sublist(pos,copy.size()).iterator();
}
公共空间删除(){
抛出新的UnsupportedOperationException();
}
}
理由是:

  • 如果我正在包装一个不透明的
    迭代器
    ,那么我复制它的唯一方法就是使用
    next()
    hasNext()
    读取它,并从中构造副本
    迭代器

  • 但在开始使用原始迭代器之前,我必须这样做

  • 简单的方法是在我开始使用迭代器之前复制迭代器的内容。(可以用懒增量复制来完成,但是实现会变得非常复杂……尤其是当考虑复制复制迭代器时)

另一个答案中提出的方法仅限于普通集合迭代器。如果你有一个包装好的迭代器,或者一个来自其他来源的迭代器(例如)没有实现
Iterable
,那么你就被烤了


即使有这个前提条件,上面的方法也不会返回迭代器的真实副本。相反,它为基础集合返回一个新的迭代器。这是一个重要的区别。除非您实际复制迭代的元素引用,否则无法保证迭代器将返回相同的序列。查看
并发…
集合类型的迭代器的记录行为。

复制
迭代器的确切含义是什么?你的意思是说它应该能够创建一个新的
迭代器
,就像它自己一样,只是从一开始就开始了?这是
Iterable
的责任。。。复制该功能是没有意义的,特别是考虑到迭代器的状态特性。。。这只会把事情搞混

如果您写道:

Iterator<Foo> iter = someIterable.iterator();
iter.next();
iter.next();
for (Foo foo : iter) {
  ...
}
Iterator iter=someIterable.Iterator();
iter.next();
iter.next();
for(Foo-Foo:iter){
...
}

您希望for循环迭代迭代器将返回的每一项,还是除前两项之外的每一项?您是否希望for循环完成后迭代器为空?

Google拥有
不可修改迭代器的唯一原因是基本上保证其集合中的不变性。他们确保您无法更改集合的内部状态

不要忘记迭代器的最初想法是,它在transveral期间是指向当前元素的指针,并且它能够管理下一个/上一个横向(对于双链接迭代器来说是反向的)到它旁边/前面的元素


迭代器不可克隆没有实际原因,很简单,克隆迭代器仍然意味着有一个迭代器指向相同的集合元素(除了它现在位于两个不同的地址空间)。除非您希望克隆的迭代器指向另一个集合,否则没有任何意义。

您可以始终实现自己的
CopyableIterator
,该迭代器实现
iterator
。然后你就可以做了

new CopyableItereator(collection);
这门课应该是这样的

class CopyableIterator implements Iterator{
Iterator iterator;
Collection collection;
int index=0;

public CopyableIterator(Collection collection){
super();
this.collection = collection;
this.iterator = collection.iterator();
}

public CopyableIterator(Collection collection, int index){
super();
this.collection =collection;
this.iterator = collection.iterator();
this.advanceToIndex(iterator,index); //This function just moves the iterator till the index.
this.index=index;
}

//Override the functions of Iterator here returning iterator.function()

@Override
public Object next(){
index++;
return this.iterator.next();
}

public CopyableIterator copy(){
return new CopyableIterator(this.collection,this.index)

}

}

免责声明:这大致是类。尚未对其进行测试。

创建了迭代器,使用所述集合支持的数据一次遍历集合中的所有对象

Iterator
几乎是al
public class IterableIterator<T> implements Iterable<T>, Iterator<T> {
    //The content of the given iterator. Will be filled by its iterators.
    private final List<T> iteratorContent = new ArrayList<T>();
    private final Iterator<T> originalIterator;
    private final Iterator<T> innerIterator;

    public IterableIterator(Iterator<T> originalIterator) {
        this(originalIterator, false);
    }

    public IterableIterator(Iterator<T> originalIterator, boolean cache) {
        if (originalIterator == null) {
            throw new IllegalArgumentException("Parameter can't be null");
        }

        this.originalIterator = originalIterator;
        if (cache) {
            while (originalIterator.hasNext()) {
                iteratorContent.add(originalIterator.next());
            }
        }

        innerIterator = iterator();
    }

    @Override
    public Iterator<T> iterator() {
        return new IteratorIterator();
    }

    @Override
    public boolean hasNext() {
        return innerIterator.hasNext();
    }

    @Override
    public T next() {
        return innerIterator.next();
    }

    @Override
    public void remove() {
        innerIterator.remove();
    }

    private class IteratorIterator implements Iterator<T> {
        private ListIterator<T> innerIterator = iteratorContent.listIterator();

        @Override
        public boolean hasNext() {
            return innerIterator.hasNext() || originalIterator.hasNext();
        }

        @Override
        public T next() {
            if (!innerIterator.hasNext() && originalIterator.hasNext()) {
                T item;
                synchronized (originalIterator) {
                    item = originalIterator.next();
                    iteratorContent.add(item);
                }
                innerIterator = iteratorContent.listIterator(innerIterator.nextIndex());
            }
            if (innerIterator.hasNext()) {
                try {
                    return innerIterator.next();
                } catch (ConcurrentModificationException e) {
                    //Quick and dirty solution if you have a concurrent modification.
                    //It can't happen from the outside, so you can easily suppose that another originalIterator
                    //from this class has been called and had added elements to the list.
                    //Best thing to do, reset the originalIterator to the current position.
                    innerIterator = iteratorContent.listIterator(innerIterator.nextIndex());
                    return innerIterator.next();
                }
            }

            throw new NoSuchElementException();
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
}
for(int i=0;i<size;i++)
{
  x = array[i];

  for(int j=i+1;j<size;j++)
  {
    y = array[j];
    if(x == y)
    {
      doSomething();
      break;
    }
}