Java容器之迭代器Iterator和枚举器Enumeration
一、Enumeration
1.1 简介
Enumeration
(列举),本身是一个接口,不是一个类。Enumeration
接口本身不是一个数据结构。但是,对其他数据结构非常重要。Enumeration
接口定义了从一个数据结构得到连续数据的手段。实现Enumeration
接口的对象,它生成一系列元素,一次生成一个。连续调用nextElement
方法将返回一系列的连续元素。
例如,要输出Vector<E> v
的所有元素,可使用以下方法:
for (Enumeration<E> e = v.elements(); e.hasMoreElements();){
System.out.println(e.nextElement());
}
1.2 源码
它的源码如下:
package java.util;
public interface Enumeration<E> {
boolean hasMoreElements();
E nextElement();
}
Enumeration
接口提供了一套标准的方法,主要通过向量的元素、哈希表的键以及哈希表中的值进行枚举。由于Enumeration
是一个接口,它的角色局限于为数据结构提供方法协议,实现该接口的对象由一系列的元素组成,可以连续地调用nextElement()
方法来得到Enumeration枚举对象中的元素。
Enumertion
接口中仅定义了下面两个方法:
- hasMoreElements(),测试此枚举是否包含更多的元素。当且仅当此枚举对象至少还包含一个可提供的元素时,才返回
true
;否则返回false
。 - E nextElement(),如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。
1.3 案例
- 使用Enumeration遍历Vector集合
import java.util.Enumeration;
import java.util.Vector;
public class EnumerationTest {
public static void main(String[] args) {
Vector<String> vector = new Vector<String>();
vector.addElement("Monday");
vector.addElement("Tuesday");
vector.addElement("Wednesday");
vector.addElement("Thursday");
Enumeration<String> elements = vector.elements();
while (elements.hasMoreElements()) {
System.out.println(elements.nextElement());
}
}
}
输出的结果为:
Monday
Tuesday
Wednesday
Thursday
- 使用Enumeration遍历HashTable(使用枚举获取key的值)
import java.util.Enumeration;
import java.util.Hashtable;
public class EnumerationTest {
public static void main(String[] args) {
Hashtable<String, String> table = new Hashtable<String, String>();
table.put("星期一", "Monday");
table.put("星期二", "Tuesday");
table.put("星期三", "Wednesday");
table.put("星期四", "Thursday");
Enumeration<String> keys = table.keys();
while (keys.hasMoreElements()) {
String element= keys.nextElement();
System.out.println(element);
}
}
}
输出的结果为:
星期三
星期二
星期四
星期一
- 使用Enumeration遍历HashTable(使用枚举获取value值)
import java.util.Enumeration;
import java.util.Hashtable;
public class EnumerationTest {
public static void main(String[] args) {
Hashtable<String, String> table = new Hashtable<String, String>();
table.put("星期一", "Monday");
table.put("星期二", "Tuesday");
table.put("星期三", "Wednesday");
table.put("星期四", "Thursday");
Enumeration<String> values= table.elements();
while (values.hasMoreElements()) {
String element= values.nextElement();
System.out.println(element);
}
}
}
输出的结果为:
Wednesday
Tuesday
Thursday
Monday
二、Iterator
2.1 简介
Iterator
(迭代器)取代了Java Collections Framework
(Java集合框架)中的Enumeration
,迭代器与枚举有两点不同:
- 迭代器允许调用者利用定义良好的语义在迭代期间从迭代器所指向的
collection
移除元素。 - 方法名称得到了改进。
2.2 源码
package java.util;
import java.util.function.Consumer;
public interface Iterator<E> {
//返回迭代器刚迭代过的元素的引用,返回值是Object,需要强制转换成自己需要的类型
boolean hasNext();
//判断容器内是否还有可供访问的元素,返回值是E
E next();
//删除迭代器刚迭代过的元素
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
hasNext()
,如果仍有元素可以迭代(next
返回了元素而不是抛出异常),则返回true
。next()
,返回迭代的下一个元素。remove()
,从迭代器指向的collection
中移除迭代器返回的最后一个元素(可选操作)。每次调用next
只能调用一次此方法。如果进行迭代时用调用此方法之外的其他方式修改了该迭代器所指向的collection
,则迭代器的行为是不确定的。如果迭代器不支持remove
操作,抛出UnsupportedOperationException
。如果尚未调用next
方法,或者在上一次调用next
方法之后已经调用了remove
方法,抛出IllegalStateException
。
2.3 案例
这里使用Iterator
遍历list
单列集合,对于map
多列集合,在调用keySet()
方法或者是entrySet()
方法之后同样也是相当于单列集合了。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorTest {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("Monday");
list.add("Tuesday");
list.add("Wednesday");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
输出结果为:
Monday
Tuesday
Wednesday
调用Iterator
的remove()
方法:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorTest {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("Monday");
list.add("Tuesday");
list.add("Wednesday");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
if ("Wednesday".equals(iterator.next())) {
iterator.remove();
}
System.out.println(list);
}
}
}
输出的结果:
[Monday, Tuesday, Wednesday]
[Monday, Tuesday, Wednesday]
[Monday, Tuesday]
注意:每次循环中最好只使用一次next()
方法,因为使用一次,指针就会往下走一个,如果在一个循环中使用了两次next()
方法,可能会出现NoSuchElementException的异常,例如:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorTest {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("Monday");
list.add("Tuesday");
list.add("Wednesday");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
if (iterator.next() != null && !"".equals(iterator.next())) {
// 逻辑处理
}
}
}
}
上面代码,循环一次,指针向后移动两位,这样在第二次循环时,第二个iterator.next()
会抛异常。
同样需要注意remove()
方法,每次调用只能够在调用了next()
方法的前提下才可以移除响应元素。如果调用了多个next()
方法后再调用remove()
方法,则移除的时最后一次调用next()
方法返回的元素。例如:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorTest {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("Monday");
list.add("Tuesday");
list.add("Wednesday");
list.add("Thursday");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
if (iterator.next() != null && !"".equals(iterator.next())) {
iterator.remove();
}
System.out.println(list);
}
}
}
输出的结果为:
[Monday, Wednesday, Thursday]
[Monday, Wednesday]
三、总结
Enumeration
接口是JDK 1.0
时推出的。使用到它的函数包括Vector
、Hashtable
等类,这些类都是JDK 1.0
中加入的,Enumeration
存在的目的就是为它们提供遍历接口。
Enumeration
本身并没有支持同步,而在Vector
、Hashtable
实现Enumeration
时,添加了同步。在JDK1.5
之后为Enumeration
接口进行了扩充,增加了泛型的操作应用。
为什么还要使用Enumeration
?这是因为java
的发展经历了很长时间,一些比较古老的系统或者类库中的方法还在使用Enumeration
接口,因此为了兼容,还是需要使用Enumeration
。已知的对于Vector
和Hashtable
的遍历还可能会使用Enumeration
。
而Iterator
是JDK 1.2
才添加的接口,Iterator
迭代器取代了Enumeration
的功能,同时增添了删除元素的方法,并且对方法的名称进行了改进。它也是为了HashMap
、ArrayList
等集合提供遍历接口。Iterator
是支持fail-fast
机制的:当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast
事件。
iterator
是快速失败的,当你在遍历的时候,如果另起一个线程来修改它(集合的内容)的结构,这时迭代器会立马感知到,引起快速失败,抛出ConcurrentModificationException
异常。
· 终于决定:把自己家的能源管理系统开源了!
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(一):从.NET IoT入
· C#实现 Winform 程序在系统托盘显示图标 & 开机自启动
· ASP.NET Core - 日志记录系统(二)
· 实现windows下简单的自动化窗口管理