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;
}
}