迭代器遍历ArrayList

ArrayList 常用遍历方法
1、for 循环遍历
2、增强 for 循环遍历
3、迭代器遍历

迭代器主要用来遍历集合,增强 for 循环底层实现也是迭代器,ListIterator 是更强大的的 Iterator 的子类型
1、只适合于 List 集合的遍历
2、它可以前后双向移动(Iterator 只能向后)
3、可以使用 set 方法替换访问过的元素
4、可以使用 listIterator(n) 创建一个一开始就指向索引为 n 的迭代器

public static void practice5() {
        ArrayList<String> practiceStr = new ArrayList<>();
        Collections.addAll(practiceStr, "apple", "cat", "dog", "big");
        log.info("for 循环遍历");
        for(int i= 0;i<practiceStr.size();i++){
            log.info(practiceStr.get(i));
        }
        log.info("增强 for 循环遍历");
        for(String element : practiceStr){
            log.info(element);
        }
        log.info("迭代器遍历");
        Iterator<String> iterator = practiceStr.iterator();
        
//        List 接口实现了 迭代器接口
//        迭代器接口作为方法的返回值时,内部其实返回了一个 接口的实现类
//        Iterator<E> 泛型接口 作为返回值,内部实际返回的是其实现类 new Itr()
//        public Iterator<E> iterator() {
//            return new ArrayList.Itr();
//        }
//        /**
//         * An optimized version of AbstractList.Itr
//         */
//        private class Itr implements Iterator<E> {
//            int cursor;       // index of next element to return
//            int lastRet = -1; // index of last element returned; -1 if no such
//            int expectedModCount = modCount;
//
//            Itr() {}
//        。。。
//        }

        while (iterator.hasNext()){
            log.info(iterator.next());
        }
    }
    log.info("list迭代器遍历");
        ListIterator<String> iteratorList = practiceStr.listIterator();
        while (iteratorList.hasNext()){
            log.info("\n");
            log.info("{}",iteratorList.nextIndex());
            log.info(iteratorList.next());
            log.info("{}",iteratorList.nextIndex());
            log.info("{}",iteratorList.previousIndex());
        }
  ListIterator<String> iteratorList1 = practiceStr.listIterator(3);
        while (iteratorLis1t.hasNext()){
            log.info("\n");
            log.info("{}",iteratorList1.nextIndex());
            log.info(iteratorList1.next());
            log.info("{}",iteratorList1.nextIndex());
            log.info("{}",iteratorList1.previousIndex());
        }

Iterator接口的定义

public interface Iterator<E> {
boolean hasNext();
E next();
//下面defalut修饰符,java8新增,用于修饰在接口中已经被具体实现方法
default void remove() {
throw new UnsupportedOperationException("remove");
}
}

重点一: remove() 方法。集合自身也有remove()方法,需要注意的是使用迭代器遍历集合时,只能通过迭代器进行add 和 remove。不支持集合本身进行 add 和 remove。查看ArrayList.java源码发现,其中实现的迭代器接口中的 next 方法中会判断集合修改次数,大于 0 时就报错 ConcurrentModificationException,这个异常本身设置的应该是并发修改异常

至于为什么有这样一个原则,是因为避免以下情况出现:
迭代器生成后,迭代器对应的集合项的位置都确定了。迭代过程中当迭代器准备给出下一项时,但该项却被Collection接口的remove方法删除,或者有一个新的项通过Collection接口的add方法插入到正在遍历项的前面,只要上述情况出现,就可能导致迭代器遍历出现问题。
迭代器调用它自己的remove方法是合法的,因为它只能删除刚才已经迭代过的对象。

while (iterator.hasNext()){
            String curElement = iterator.next();
            log.info(curElement);
            if(curElement.equals("cat")){
                iterator.remove();
            }
        }
// 使用迭代器的remove正常
while (iterator.hasNext()){
            String curElement = iterator.next();
            log.info(curElement);
            if(curElement.equals("apple")){
                practiceStr.remove("apple");
            }
        }
// 使用集合的remove报错:java.util.ConcurrentModificationException

ArrayList 迭代器接口中的 next 方法源码

 public E next() {
            checkForComodification(); // 检查修改次数
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }
        
 final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
        
    protected transient int modCount = 0;
    int expectedModCount = modCount;
  

重点二:一次hasNext()后使用了多次next()方法 TODO

每次调用next()方法之前必须要调用hastNext()方法进行检测;
如果没有调用并且没有下一个元素,直接调用next()方法会抛出 NoSuchElementException异常。
同理如果调用了一次 hasNext() 方法,但是调用了多次next()方法,依旧会抛出异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值