关于Java迭代器(Iterator)的思考

Java Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法,可用于迭代 ArrayList 和 HashSet 等集合。

在我们使用

for(... : ...)

去遍历集合中的所有元素时,其实就隐式地使用了迭代器(Iterator)。

遍历集合的两种方法

通常来说,遍历集合中的元素主要有以下两种方法。

//method1
List<String> list = ...;
for(String str : list) {
	System.out.println(str);
}
//method2
List<String> list = ...;
Iterator<String> iter = list.iterator();
while(iter.hasNext()) {
	String str = iter.next();
	System.out.println(str);
}

对于第二种方法来说,其实是显式地定义了一个Iterator类型的对象,它有iterator()方法,调用该方法可以获取一个迭代器。

迭代器有三个基本操作,分别是 next 、hasNext 和 remove。

调用 it.next() 会返回迭代器的下一个元素,并且更新迭代器的状态。

调用 it.hasNext() 用于检测集合中是否还有元素。

调用 it.remove() 将迭代器返回的元素删除。

Iterator是Java中的一个接口,位于java.util 包中,使用前需要引入它,语法格式如下:

import java.util.Iterator; // 引入 Iterator 类

两种方法的比较

下面,我们来比较一下这两种方法有何不同。

我们先分别运行一下下面的两段代码。

public class Test {
	
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>(Arrays.asList("Apple","Orange","Peach"));
		
		for(String str : list) {
			System.out.println(str);
		}
		
	}
}
public class Test {
	
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>(Arrays.asList("Apple","Orange","Peach"));
		
		Iterator<String> iter = list.iterator();
		while(iter.hasNext()) {
			String str = iter.next();
			System.out.println(str);
		}
		
	}
}

我们发现它们的运行结果是一样的。这样看它们好像没有什么差别,而且第一种写法要简单一些,代码量更少。

删除元素

下面我们比较一下当从集合中删除元素时,这两种写法的区别。

public class Test {
	
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>(Arrays.asList("Apple","Orange","Peach"));
		
		for(String str : list) {
			list.remove(str);
		}
		
		System.out.println(list);
		
	}
}

当我们运行上面这段代码时,出现了报错。
在这里插入图片描述可以通过根据异常定位到报错的地方:
在这里插入图片描述当我们使用Java中的foreach循环时,其实编译器会根据list对象创建一个Iterator的迭代器。我们对list进行的增删操作的具体实现都必须经过Iterator。在Iterator创建的时候modCount被赋值给了expectedModCount,但是调用list的add和remove方法的时候不会同时自动增减expectedModCount,这样就导致两个count不相等,从而抛出异常。

我们再试试下面这种写法。

public class Test {
	
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>(Arrays.asList("Apple","Orange","Peach"));
		
		Iterator<String> iter = list.iterator();
		while(iter.hasNext()) {
			String str = iter.next();
			list.remove(str);
		}
		
		System.out.println(list);
		
	}
}

运行之后,出现了和上面一样的报错信息。与上一种写法相比,这里的Iterator被显式地定义出来了,但是同样出现了调用list的remove方法的时候不会同时自动增减expectedModCount的问题,这样就导致两个count不相等,从而抛出异常。

那应该怎样在遍历List的同时删除元素呢,我们看一下下面这种写法。

public class Test {
	
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>(Arrays.asList("Apple","Orange","Peach"));
		
		Iterator<String> iter = list.iterator();
		while(iter.hasNext()) {
			String str = iter.next();
			if(str.endsWith("e")) {
				iter.remove();
			}
		}
		
		System.out.println(list);
		
	}
}

最后的运行结果如下:
在这里插入图片描述
我们可以看到,这里成功的删除了以e结尾的两个字符串。为什么使用iter.remove()就可以成功删除List中的元素呢?这是因为在Iterator中的remove方法在删除元素后会自动调整迭代器指向的元素,也会自动增减expectedModCount的值,所以不会出现之前的报错。

使用自己的迭代器

上面我们都是使用的Java标准库里的Iterator接口,那能否定义自己的MyIterator类(接口)呢?

答案是肯定的。并且在很多时候,为自己设计的抽象数据类型(ADT)增加一个迭代器是一个很不错的设计模式(Iterator Pattern),用户可以用之前已经非常熟悉的迭代器方法来遍历你设计的ADT中的元素。

在Java的标准库中定义了一个Iterable接口,而实现该接口的集合对象是可遍历迭代的。
在这里插入图片描述
这里的Ierator是迭代器的接口,也在Java标准库中有定义。基本结构如下。
在这里插入图片描述
而所谓的Iterator pattern就是指让自己的集合类实现Iterable接口,并实现自己独特的Iterator迭代器(重写hasNext, next, remove方法),允许客户端利用这个迭代器进行显式或隐式的迭代遍历。

下面是一个实现样例。

//实现Iterable<E>接口
public class Pair<E> implements Iterable<E> {
	private final E first, second;
	public Pair(E f, E s) { first = f; second = s; }
	//重写iterator方法
	//返回自己的迭代器
	public Iterator<E> iterator() {
		return new PairIterator();
	}
	//构建自己的Iterator
	private class PairIterator implements Iterator<E> {
		private boolean seenFirst = false, seenSecond = false;
		//Override hasNext方法
		public boolean hasNext() { return !seenSecond; }
		//Override next方法
		public E next() {
			if (!seenFirst) { seenFirst = true; return first; }
			if (!seenSecond) { seenSecond = true; return second; }
			throw new NoSuchElementException();
		}
		//Override remove方法
		//这里不允许删除元素
		public void remove() {
			throw new UnsupportedOperationException();
		}
	}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值