Java学习之迭代器


迭代器

Demo001---------阿里云基础P184
	迭代器Enumeration和Iterator的区别
	1、函数接口不同
        Enumeration只有两个函数接口。通过Enumeration,我们只能读取集合的数据,而不能对数据进行修改
        Iterator只有三个函数接口。Iterator除了能读取集合的数据之外,也能对数据进行删除操作
	2、Iterator支持fail-fast机制,而Enumeration不支持
		Enumeration是Java1.0之后添加的接口。使用到它的函数包括Vector、Hashtable等类;这些类都是JDK1.0中加入的。Enumeration存在的目的就是为他们提供遍历接口。Enumeration本省并不支持同步,而是在Vector、Hashtable实现Enumeration时添加的同步
		Iterator是JDK1.2才添加的接口,他也是为了HashMap、ArrayList等集合提供遍历接口。Iterator是支持fail-fast机制的,当有多个线程对同一集合进行操作的时候,就有可能产生fail-fast事件。
		注:Enumeration迭代器只能遍历 Vector、Hashtable等这些古老的集合,因此通常使用Iterator;除非在极端情况下不得不使用Enumeration的时候才会使用
	
    使用迭代器删除元素而引起的ConcurrentModifcationException(CME)并发修改异常
    原因:Java集合汇中运用了fail-fast机制进行设计,一旦使用不当,就会触发fail-fast机制设计的代码,就会发生非预期情况
        触发错误的代码:
            List<String> usernames=new ArrayList<String>(){{
                add("user");
                add("User");
                add("userlyz");
                add("u");
            }};
            for(String username:usernames){
                if(username.equals("User")){
                    usernames.(username);
                }
            }
    对于编译后的class进行反编译,可以发现foreach其实是依赖了 do while循环和Iterator实现的
    爆出这个错误是因为modCount和expectedModCount不相等导致的
        modCount表示该集合实际被修改的次数
        expectedModCount是ArrayList中的一个内部类--Itr中的成员变量;表示这个迭代器预期该集合被修改的次数
    fail-safe机制
        为了避免触发fail-fast机制,我们可以使用Java中提供的一些采用了fail-safe机制的集合类
            这样的集合容器,在遍历上不是直接在集合内容上访问的,而是先复制原有集合内容在拷贝的集合上进行遍历
            java.util.concurrent下的容器都是fail-safe的,可以在多线程并发使用,并发修改
            代码说明
                        List<String> usernames=new CopyOnWriteArrayList<String>(){{
                            add("user");
                            add("User");
                            add("userlyz");
                            add("u");
                        }};
                        for(String username:usernames){
                            if(username.equals("User")){
                                usernames.(username);
                                System.out.println(username+"已经删除了");
                            }
                        }
                        System.out.println(usernames);
            输出
                User已经删除了
                [user, userlyz, u]
        这样虽然是避免了ConcurrentModificationException,但是迭代器并不能访问修改之后的内容
            代码如下
                List<String> usernames=new CopyOnWriteArrayList<String>(){{
                    add("user");
                    add("User");
                    add("userlyz");
                    add("u");
                }};
                Iterator it= usernames.iterator();
                for(String username:usernames){
                    if(username.equals("User")){
                        usernames.(username);
                        System.out.println(username+"已经删除了");
                    }
                }
                System.out.println(usernames);
                System.out.println("---------------------");
                while(it.hasNext()){
                    System.out.println(it.next());
                }
            输出
                User已经删除了
                [user, userlyz, u]
                ---------------------
                user
                User
                userlyz
                u
    CopyOnWrite 是一种程序设计中的优化策略。从一开始大家都在共享同一个内容,当某人想要修改这个内容的时候,才会真正
        把内容Copy出去形成一个新的内容然后再该,这是一种延时懒惰策略
            他的add/remove等写方法是需要加锁;目的是为了避免Copy处N个副本,导致并发读写
            他的读方法是没有加锁的,所以读到的数据可能不是最新的
        所以CopyOnWrite容器是一种读写分离的思想
        而Vector在读写的时候使用同一个容器,读写互斥,同时只能做一件事儿。
    所以应该在遍历的同时删除ArrayList中的元素
        1、使用普通的for循环进行操作:可能会出现漏删的情况
        2、直接使用Iterator进行操作:直接使用Iterator提供的remove方法
            List<String> userNames = new ArrayList<String>() {{
                add("Hollis");
                add("hollis");
                add("HollisChuang");
                add("H");
            }};
            Iterator iterator = userNames.iterator();
            while (iterator.hasNext()) {
                if (iterator.next().equals("Hollis")) {
                    iterator.remove();
                    }
                }
            System.out.println(userNames);
        3、使用java8中提供的 filter过滤
            代码:
                List<String> userNames = new ArrayList<String>() {{
                   add("Hollis");
                   add("hollis");
                   add("HollisChuang");
                   add("H");
               }};
               userNames = userNames.stream().filter(userName -> !userName.equals("Hol lis")).collect(Collectors.toList());
               System.out.println(userNames);
        4、使用增强for循环:某个元素只包含一个的话,只要删除之后立即结束循环体,不再继续遍历下去
        5、使用fail-safe的集合类:

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=33i3ekx3p38k8


文章作者: 毛豆不逗比
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 毛豆不逗比 !
  目录
{% include '_third-party/exturl.swig' %} {% include '_third-party/bookmark.swig' %} {% include '_third-party/copy-code.swig' %} + {% include '_custom/custom.swig' %}