Colleciton概述
Collection 接口是 List、Set 和 Queue 接口的父接口,该接口里定义的方法既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合。
Collection是保存单值集合的最大父接口。JDK不提供此接口的任何直接实现,而是提供更具体的子接口(如 Set 和 List)实现。
在 Java5 之前,Java 集合会丢失容器中所有对象的数据类型,把所有对象都当成 Object 类型处理;从 Java5 增加了泛型以后,Java 集合可以记住容器中对象的数据类型
Collection接口继承树
使用Iterator接口遍历集合元素
Iterator接口:
Iterator对象称为迭代器(设计模式的一种),主要用于遍历 Collection 集合中的元素。
所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象。
Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力。如果需要创建 Iterator 对象,则必须有一个被迭代的集合。
操作原理:Iterator是专门的迭代输出接口,所谓的迭代输出就是将元素一个个进行判断,判断其是否有内容,如果有内容则把内容取出。
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("Jerry");
list.add("Tom");
list.add("Rose");
// 使用迭代器进行相关遍历
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()) { // 判断下一个元素之后有值
System.out.print(iterator.next() + "\t");
}
}
}
在调用iterator.next()方法之前必须要调用iterator.hasNext()进行检测。若不调用,且下一条记录无效,直接调用iterator.next()会抛出NoSuchElementException异常。例如将以上例子做以下修改:
// 使用迭代器进行相关遍历
Iterator<String> iterator = list.iterator();
while(true) {
System.out.print(iterator.next() + "\t");
}
执行时报错:
正常情况下,一个集合要把内容交给Iterator 输出,但是集合操作中也存在一个remove()方法,如果在使用Iterator输出时,集合自己调用了删除方法,则很可能会出现运行时的错误。将以上例子做以下更改:
while(iterator.hasNext()) { // 判断下一个元素之后有值
String element = iterator.next();
if("Jerry".equals(element)) {
list.remove(element); // 应该使用iterator。remove();
}else {
System.out.println(element + "\t");
}
System.out.print("删除元素之后的集合:" + list);
}
执行时报错:
ListIterator接口:
Iterator 接口的主要功能是由前向后单向输出,而此时如果想实现由后向前或是由前向后的双向输出,则就必须使用Iterator的子接口ListIterator。
与Iterator接口不同的是,ListIterator接口只能通过List接口实例化,即只能输出List接口中的内容。
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("Jerry");
list.add("Tom");
list.add("Rose");
ListIterator<String> iterator = list.listIterator();
while(iterator.hasNext()) { // 判断下一个元素之后有值
System.out.print(iterator.next() + "\t"); // 由前向后输出
}
System.out.print("\n");
while(iterator.hasPrevious()){
System.out.print(iterator.previous() + "\t"); // 由后向前输出
}
}
}
以上代码执行结果如下:
Jerry Tom Rose
Rose Tom Jerry
Iterator 和 ListIterator 的区别:
1)Iterator 可用来遍历 Set 和 List 集合,但是 ListIterator 只能用来遍历 List。
2)Iterator 对集合只能是前向遍历, ListIterator 既可以前向也可以后向。
3)ListIterator 实现了 Iterator 接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。
快速失败(fail-fast)和安全失败(fail-safe)的区别:
1)Iterator 的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响。
2)java.util包下面的所有的集合类都是快速失败的,而 java.util.concurrent 包下面的所有的类都是安全失败的。
3)快速失败的迭代器会抛出 ConcurrentModificationException 异常,而安全失败的迭代器永远不会抛出这样的异常。
把链表变为数组相关的内容进行遍历
String[] strArray = new String[list.size()];
list.toArray(strArray);
for(int i = 0; i<strArray.length; i++) {
System.out.println(strArray[i]);
}
使用for或增强for循环遍历集合元素
Java 5 提供了 foreach 循环迭代访问 Collection。Java8 在集合父接口java.lang.Iterable中新增了一个default实现方法forEach方法。
for(int i = 0; i < list.size(); i++){
System.out.println(list.get(i));
}
for(String str : list){
System.out.println(str);
}
for(Person person: list){
System.out.println(person.getName());
}
list.forEach(person -> {
System.out.println(person.getName());
});
使用Enumeration接口遍历集合元素
Enumeration 接口是 Iterator 迭代器的 “古老版本”,是JDK1.0时推出的。
public class Test {
public static void main(String[] args) {
Enumeration stringEnum = new StringTokenizer("a-b*c-d-e-f-g", "-");
while(stringEnum.hasMoreElements()){
Object obj = stringEnum.nextElement();
System.out.print(obj + "\t");
}
System.out.println();
Vector vector = new Vector();
vector.add("Jerry");
vector.add("tom");
Enumeration<String> enu = vector.elements();
while(enu.hasMoreElements()){
System.out.print(enu.nextElement() + "\t");
}
}
}
Enumeration 接口和 Iterator 接口的区别:
1)Enumeration 速度是 Iterator 的 2 倍,同时占用更少的内存。
2)但是,Iterator 远远比 Enumeration安全,因为其他线程不能够修改正在被 iterator 遍历的集合里面的对象。
3)同时,Iterator 允许调用者删除底层集合里面的元素,这对 Enumeration 来说是不可能的。