迭代器输出
1.迭代输出Iterator----只能从前向后输出----(Collection子类都支持(List和Set集合))
调用Collection集合子类的Iterator方法取得内置的迭代器,使用以下输出格式:
public static void main(String[] args) {
List<String> list=new ArrayList<>();
list.add("pick");
list.add("happy");
//取得ArrayList的迭代器
Iterator<String> iterator=list.iterator();
while(iterator.hasNext())
{
System.out.println(iterator.next());
}
}
2.双向迭代接口ListIterator----------(只有List接口可以,Set接口不支持)
boolean hasNext( ); 判断是否还有元素
E next( ); 取得下一个元素
boolean hasPervious( ); 判断是否有上一个元素
E previous( ):取得上一个元素
public static void main(String[] args) {
List<String> list=new ArrayList<>();
list.add("pick");
list.add("happy");
//取得ArrayList的迭代器
ListIterator<String> listiterator=list.listIterator();
while(listiterator.hasNext())
{
System.out.println(listiterator.next()); //pick happy
}
while (listiterator.hasPrevious())
{
System.out.println(listiterator.previous());//happy pick
}
}
注意:要想从后向前遍历,首先至少要从前向后遍历一次才可以使用。
3.Enumeration枚举输出----只有Vector类支持
public boolean hasMoreElements() :判断是否有下一个元素
public E nextElements():取得下一个元素
//Enumeration
public class Iterator1 {
public static void main(String[] args) {
Vector<String> vector=new Vector<>();
vector.add("pick");
vector.add("happy");
//取得ArrayList的迭代器
Enumeration<String> enumeration=vector.elements();
while(enumeration.hasMoreElements())
{
System.out.println(enumeration.nextElement()); //pick happy
}
}
}
4.for-each输出(所有子类都满足)
能使用for-each输出的本质是各个集合类都内置了迭代器
在for-each添加或删除元素会有并发修改异常
fail-fast
产生ConcurrentModificationException异常:
public static void main(String[] args) {
List<String> list=new ArrayList<>();
Collections.addAll(list,"A","B","C","D","B","a");
Iterator<String> iterator=list.iterator();
while(iterator.hasNext())
{
String str=iterator.next();
if(str.equals("B")) {
list.remove("B"); //使用list.remove发生异常
continue;
}
System.out.println(str);
}
}
ConcurrentModificationException异常发生在Collection集合使用迭代器遍历时,使用了集合类提供的修改集合内容方法报错。而如果使用Iterator迭代器的remove( )不会出现此错误。
public class Iterator1 {
public static void main(String[] args) {
List<String> list=new ArrayList<>();
Collections.addAll(list,"A","B","C","D","B","a");
Iterator<String> iterator=list.iterator();
while(iterator.hasNext())
{
String str=iterator.next();
if(str.equals("B")) {
iterator.remove(); //使用list.remove发生异常
continue;
}
System.out.println(str); // A C D a
}
}
}
ConcurrentModificationException异常产生分析:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
Collection集合中的modCount表示当前集合修改的次数
expectedModCount 是迭代器中记录当前集合的修改次数
当取得集合迭代器(即调用List.Iterator( )),expectedModCount =modCount,即迭代器是当前集合的一个副本。
在集合的add和remove方法中会将modCount++,在迭代器遍历时next( )时会判断expectedModCount 、modCount是否相等,不相等将会抛异常ConcurrentModificationException。
public static void main(String[] args) {
List<String> list=new ArrayList<>();
Collections.addAll(list,"A","B","C","D","B","a");
//此时modCount=6
Iterator<String> iterator=list.iterator();
//此时调用list.iterator(),取得集合迭代器,expectedModCount =modCount=6
while(iterator.hasNext())
{
//下一次循环调next方法,会调用checkForComodification判断副本的 expectedModCount 和集合的modCount是否相等,
// 不相等抛异常
String str=iterator.next();
if(str.equals("B")) {
list.remove("B"); //使用list.remove发生异常
//调用list.remove(),modCount=7,然后进行下一次循环
continue;
}
System.out.println(str); // A C D a
}
}
快速失败策略保证了所有用户在进行迭代遍历集合时,拿到的数据一定是最新的数据(避免“脏读”产生)。
在这里脏读是:假如线程1在遍历迭代器中元素,线程2在修改元素,那么线程1读到的数据就有问题,即是脏读,但是抛出异常后,线程1就知道遍历的元素有问题。
抛异常尽量保证了在多线程情况下数据不会产生脏读,即若有线程并发修改集合结构时,向同时在遍历此集合的线程发出一个异常,通知其集合数据已经修改。
产生ConcurrentModificationException异常的类有?
ArrayList Vector (尽管是synchronized) LinkedList HashMap Hashtable
为什么调用迭代器的remove可以?
因为会把副本的expectedModCount更新到最新值。
fail-safe
不产生 ConcurrentModificationException异常
juc包下所有线程安全集合(CopyOnWriteArrayList ConcurrentHashMapt)
总结:在迭代器遍历时,不要修改集合内容。