迭代器的应用场景:

1、对集合进行增加删除,禁止使用foreach,循环的动态操作
2、倒序遍历
3、遍历循环

步入正题:为何禁止在foreach内进行增删?

先看一下代码:

/**
         *         正例:
         *         Iterator<String> iterator = list.iterator();
         *         while (iterator.hasNext()) {
         *             String item = iterator.next();
         *             if (删除元素的条件) {
         *                 iterator.remove();
         *             }
         *         }
         *         反例:
         *         List<String> list = new ArrayList<String>();
         *         list.add("1");
         *         list.add("2");
         *         for (String item : list) {
         *             if ("1".equals(item)) {
         *                 list.remove(item);
         *             }
         *         }
         */

这段代码是,在阿里的开发手册中的一段代码。

我们先看下面场景:

/**
         * 场景一:对集合进行删除,增加、for循环
         * 错误:这里会报出数据越界异常,
         * 因为:remove掉一个元素后,整个长度发生变化,所以发生异常
         * 改进:采用forList.size()动态
         */
        List<String> forList = new ArrayList<>();
        forList.add("a");
        forList.add("b");
        forList.add("c");
        int length = forList.size();
        for (int i = 0; i < length; i++) {
            if ("a".equals(forList.get(i))) {
                forList.remove(i);
            }
        }
        System.out.println(forList);
        /**
         * 产生新问题:
         * 错误:运行便会发现:将b移除不完整,
         * 因为:删除后整个游标向下,数组向上,刚好空出1个位置,
         * 紧接着的第二位没有进行比对,所以产生问题
         * 解决:数据长度减一与游标保持统一
         */
        List<String> forList1 = new ArrayList<>();
        forList1.add("a");
        forList1.add("b");
        forList1.add("b");
        forList1.add("c");
        for (int i = 0; i < forList1.size(); i++) {
            if ("b".equals(forList1.get(i))) {
                forList1.remove(i);
                i--;
            }
        }
        System.out.println(forList1);

通过上个场景,知道在for循环内,为啥不建议用remove/add

在foreach循环内,再接着看下面这个场景?

/**
         * 场景二:
         * foreach循环,的remove/add操作
         */
        List<String> forEach = new ArrayList<>();
        forEach.add("a");
        forEach.add("b");
        forEach.add("c");
        for (String each : forEach) {
            if ("a".equals(each)) {
                forEach.remove(each);
            }
        }
        /**
         * 产生的异常:
         *   Exception in thread "main" java.util.ConcurrentModificationException
         *             at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
         *             at java.util.ArrayList$Itr.next(ArrayList.java:859)
         */
        /**
         * 源码:Itr实现了Iterator接口(删减部分)
         *  private class Itr implements Iterator<E> {
         *         @Override
         *         @SuppressWarnings("unchecked")
         *         public void forEachRemaining(Consumer<? super E> consumer) {
         *             Objects.requireNonNull(consumer);
         *             final int size = ArrayList.this.size;
         *             int i = cursor;
         *             if (i >= size) {
         *                 return;
         *             }
         *             final Object[] elementData = ArrayList.this.elementData;
         *             if (i >= elementData.length) {
         *                 throw new ConcurrentModificationException();
         *             }
         *             while (i != size && modCount == expectedModCount) {
         *                 consumer.accept((E) elementData[i++]);
         *             }
         *             // update once at end of iteration to reduce heap write traffic
         *             cursor = i;
         *             lastRet = i - 1;
         *             checkForComodification();
         *         }
         *
         *          如果有更改则抛出ConcurrentModificationException异常,
         *
         *         final void checkForComodification() {
         *         之前的版本不等于,当前的版本,判断为数据更新了。
         *         那么?为什么产生这样的判断呢,因为你删除后变为新数组,来不及
         * 更新版本,jvm不知道你当前数据状态,是否变化,无法再进行遍历
         *             if (modCount != expectedModCount)
         *                 throw new ConcurrentModificationException();
         *         }
         *     }
         */
        /**
         * 改进:
         *
         */
        List<String> forEachIterator = new ArrayList<>();
        forEachIterator.add("a");
        forEachIterator.add("b");
        forEachIterator.add("c");
        java.util.Iterator<String> iterator = forEachIterator.iterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            if ("a".equals(next)) {
                iterator.remove();
            }
        }
这里:foreach实现的就是迭代器。

补充:倒序循环

/**
         * 场景三:
         * 应用:倒序遍历
         */
        List<String> forEachIteratorDown = new ArrayList<>();
        forEachIteratorDown.add("a");
        forEachIteratorDown.add("b");
        forEachIteratorDown.add("c");
        ListIterator<String> item = forEachIteratorDown.listIterator();
        //这里需要先将指针移向最后一位,再进行倒叙
        while (item.hasNext()) {
            item.next();
        }
        while (item.hasPrevious()) {
            String previous = item.previous();
            System.out.println(previous);
        }
更多技术资讯可关注:itheimaGZ获取

Iterator迭代器解决[为何禁止在foreach内增删]的更多相关文章

  1. [设计模式] Iterator - 迭代器模式:由一份奥利奥早餐联想到的设计模式

    Iterator - 迭代器模式 目录 前言 回顾 UML 类图 代码分析 抽象的 UML 类图 思考 前言 这是一包奥利奥(数组),里面藏了很多块奥利奥饼干(数组中的元素),我将它们放在一个碟子上慢 ...

  2. 为什么阿里巴巴禁止在 foreach 循环里进行元素的 remove/add 操作--java.util.ConcurrentModificationException

    摘要 foreach循环(Foreach loop)是计算机编程语言中的一种控制流程语句,通常用来循环遍历数组或集合中的元素. 在阿里巴巴Java开发手册中,有这样一条规定: 但是手册中并没有给出具体 ...

  3. [C# 设计模式] Iterator - 迭代器模式:我与一份奥利奥早餐的故事

    Iterator - 迭代器模式 目录 前言 回顾 UML 类图 代码分析 抽象的 UML 类图 思考 前言 这是一包奥利奥(数组),里面藏了很多块奥利奥饼干(数组中的元素),我将它们放在一个碟子上慢 ...

  4. C#:iterator 迭代器/partial class 分布类/泛型

    C#:iterator 迭代器/partial class 分布类/泛型 iterator 迭代器 写个最简单的迭代,(迭代一个字符串数组): 1.实现接口中的方法: 1 using System; ...

  5. ES6笔记(6)-- Set、Map结构和Iterator迭代器

    系列文章 -- ES6笔记系列 搞ES6的人也是够无聊,把JS弄得越来越像Java.C++,连Iterator迭代器.Set集合.Map结构都出来了,不知道说什么好... 一.简单使用 1. iter ...

  6. 设计模式(十五):Iterator迭代器模式 -- 行为型模式

    1.概述 类中的面向对象编程封装应用逻辑.类,就是实例化的对象,每个单独的对象都有一个特定的身份和状态.单独的对象是一种组织代码的有用方法,但通常你会处理一组对象或者集合. 集合不一定是均一的.图形用 ...

  7. STL之iterator(迭代器)

    3.迭代器简单介绍 除了使用下标来訪问vector对象的元素外,标准库还提供了訪问元素的方法:使用迭代器.迭代器是一种检查容器内元素而且遍历元素的数据类型. 百科释义: 迭代器(iterator)是一 ...

  8. Python 中 Iterator(迭代器)和Iterable(迭代对象)的区别

    直接可以用作for循环的数据类型有以下几种: tuple.list.dict.str等, 上述数据类型可以用作for循环的叫做可迭代对象Iterable.可以使用isinstance判断一个对象是否是 ...

  9. 增强for、iterator迭代器

    因为初学java,对部分语法还模棱两可, 在做练习的时候,用增强for遍历字符串编译报错 所以来复习下增强for原理和适用范围 一.增强for概念 增强for(也成为for each循环)是JDK 1 ...

随机推荐

  1. java将HSSFWorkbook生成的excel压缩到zip中

    思路:1.写入输入流中. 2.将输入流加到ZipOutputStream压缩流中 List<DocumentModel> list = null; try { list = documen ...

  2. Java 知识点(一)

    博主对 Java知识点的整理基于 c语言,整理内容为 Java的重点及与 c语言的差异点或编程通要知识点.水平有限,欢迎指正.(参考书籍<Java 核心技术 卷Ⅰ>) Java 的类名:名 ...

  3. php速成_day1

    一.概述 1.什么是PHP PHP ( Hypertext Preprocessor ),是英文超级文本预处理语言的缩写.PHP 是一种 跨平台.嵌入式的服务器端执行的描述语言,是一种在服务器端执行的 ...

  4. Ivory Coast Map

    Fun Facts about Cote d'Ivoire The Republic of Cote d'Ivoire (previously known as the Ivory Coast) is ...

  5. 你需要知道的 N 种抓取 dump 的工具

    原总结注册表debug调试dump转储文件windbgprocdump 前言 今天,向大家介绍几种可以抓取应用程序转储文件的工具及基本使用方法.更详细的用法,请参考每个工具对应的帮助文档.如果你还不清 ...

  6. Ackermann函数

    Ackermann函数定义如下: 若m=0,返回n+1. 若m>0且n=0,返回Ackermann(m-1,1). 若m>0且n>0,返回Ackermann(m-1,Ackerman ...

  7. ZJNU 1422 - 碰撞的小球

    完全弹性碰撞可以视作互相穿过 所以直接考虑只有单个小球的时候,从板子上滑下所需要的时间即可 最后以30000为界分开流读入与缓冲区优化的io方法 //Case4用缓冲区io优化会WA??? /* Wr ...

  8. Vue专题-生命周期

    有时候,我们需要在实例创建过程中进行一些初始化的工作,以帮助我们完成项目中更复杂更丰富的需求开发,针对这样的需求,Vue提供给我们一系列的钩子函数. 本文详细介绍了Vue实例在创建和销毁的过程中,我们 ...

  9. uboot对Flash和DDR的分区管理

    1.uboot阶段对Flash的分区 (1).所谓分区,就是对Flash进行分块管理. (2).PC机等产品中,因为大家都是在操作系统下使用硬盘的,整个硬盘由操作系统统一管理,操作系统会使用文件系统帮 ...

  10. Django学习---多人博客项目(1)

    一.创建项目和应用 ​ 在Pycharm中用Django模板创建一个工程文件 创建项目 python manage.py startproject 项目名 . 创建应用 python manage.p ...