• Java集合里的一些“坑”


      这里主要谈下Java集合在使用中容易被忽略、又容易出现的两个“坑”,一个是集合与数组互相转换,另一个是集合遍历删除。主要通过代码演示。

      一.集合与数组互相转换中的“坑”  

    //Test1.java
    package com.itszt.test0419;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.List;
    /**
     * 集合与数组互相转换,含list集合元素反序排列
     */
    public class Test1 {
        public static void main(String[] args) {
            //一个集合对象
            ArrayList<String> list=new ArrayList<>();
            list.add("a");
            list.add("b");
            list.add("c");
            list.add("d");
            list.add("e");
            //集合元素正反序转换
            System.out.println("正序---list = " + list.toString());
            Collections.reverse(list);
            System.out.println("反序---list = " + list.toString());
            Collections.reverse(list);
            System.out.println("恢复初始状态---list"+list);
            //(1)集合转数组
            Object[] listArray1 = list.toArray();//方法1
            System.out.println("方法1---listArray1 = " + Arrays.toString(listArray1));
            String[] listArray2 = list.toArray(new String[list.size()]);//方法2
            System.out.println("方法2---listArray2 = " + Arrays.toString(listArray2));
            String[] listArray3=new String[list.size()];//方法3
            for(int i=0;i<list.size();i++){
                listArray3[i]=list.get(i);
            }
            System.out.println("方法3---listArray3 = " + Arrays.toString(listArray3));
            //(2)数组转集合
            List<Object> asList = Arrays.asList(listArray1);
            /*
                此时返回的ArrayList是Arrays的一个私有静态内部类,
                可以遍历查询,但是不可以像普通集合那样增删元素
             */
            System.out.println("asList = " + asList.toString());
            /*
                asList.add("f");
                asList.remove("a");
                //若增删元素,均会抛出异常 java.lang.UnsupportedOperationException
             */
            //下述方法成功地将数组转化为集合
            ArrayList arrayList = new ArrayList<>(asList);
            arrayList.add("f");
            arrayList.remove("a");
            System.out.println("arrayList = " + arrayList.toString());
        }
    }

      二.集合遍历删除中的“坑”  

    //Test2.java
    package com.itszt.test0419;
    import java.util.ArrayList;
    import java.util.Iterator;
    /**
     * 集合遍历删除中的坑
     * 推荐对JAVA集合进行遍历删除时用迭代器
     */
    public class Test2 {
        public static void main(String[] args) {
            //一个集合对象
            ArrayList<String> list=new ArrayList<>();
            list.add("a");
            list.add("b");
            list.add("c");
            list.add("d");
            list.add("e");
    
            //下面是错误的遍历删除方式,抛出异常:java.util.ConcurrentModificationException
            /*for(String s:list){
                list.remove(s);
            }*/
            //其实,上述代码在执行时,会转换成迭代器执行,但删除操作却用了错误的方法,如下所示:
            /*for(Iterator<String> it=list.iterator();it.hasNext();){
                String next = it.next();
                list.remove(next);
            }*/
    
            //若将上述代码予以改写,就可以正常执行:
            /*for(Iterator<String> it=list.iterator();it.hasNext();){
                it.remove();
            }
            System.out.println("list = " + list.size());*/
    
            /*
                另外,下述方式不会报异常,但只能遍历删除部分元素。
                这是因为:该方法中有一个严重的错误。
                当一个元素被删除时,列表的大小缩小并且下标变化,
                所以当你想要在一个循环中用下标删除多个元素的时候,它并不会正常生效。
             */
            /*for(int i=0;i<list.size();i++){
                list.remove(i);
            }
            System.out.println("list = " +
                    list.size()+"---"+
                    list.toString());*/
    
            //下述方法可以清空集合内的所有元素
            /*list.clear();
            System.out.println("list = " +list.size());*/
    
            //下述方式可以正确地删除指定内容的元素
            /*for(int i=0;i<list.size();i++){
                if("a".equals(list.get(i))){
                    list.remove(i);
                }
            }
            System.out.println("list = " + list.toString());*/
    
            /**
             * 那么,为什么List集合使用迭代后,就不能再用集合自身的删除方法list.remove(i)了呢?
             * 这是因为,ArrayList与Iterator混合使用时会导致各自的状态出现不一样,最终出现异常。
             * ArrayList采用size属性来维护自已的状态,而Iterator采用cursor来来维护自已的状态。
             * 当size出现变化时,cursor并不一定能够得到同步,除非这种变化是Iterator主动导致的。
             * Iterator.remove方法导致ArrayList列表发生变化时,会自动更新cursor来同步这一变化。
             * 但其他方式导致的ArrayList变化,Iterator是无法感知的。
             * ArrayList不会主动通知Iterator,这将有损效率。
             * 为了防止状态不一致可能引发的无法设想的后果,
             * Iterator会经常做checkForComodification检查,以防有变。
             * 如果有变,则以异常抛出,所以就抛出了上面的异常:
             * java.util.ConcurrentModificationException
             * 再来比较下面两种遍历删除方法:
             */
    
            //错误的删除方法 抛出异常:java.util.ConcurrentModificationException
            /*for(String s:list){
                if("a".equals(s)){
                    list.remove(s);
                }
            }
            System.out.println("list = " + list.toString());*/
    
            //正确的删除方法
            /*for(Iterator<String> it=list.iterator();it.hasNext();){
                if("a".equals(it.next())){
                    it.remove();
                }
            }
            System.out.println("list = " + list.toString());*/
            /**
             * 上述两种方法的不同结果是因为:
             *.next()必须在.remove()之前调用。
             * 在一个foreach循环中,编译器会使.next()在删除元素之后被调用,
             * 因此就会抛出ConcurrentModificationException异常。
             * 总之:
             * Iterator 支持从源集合中安全地删除对象,
             * 只需在 Iterator 上调用 remove() 即可。
             * 这样做的好处是可以避免 ConcurrentModificationException ,
             * 这个异常顾名思意:当打开 Iterator 迭代集合时,同时又在对集合进行修改。
             * 为此,在对集合迭代时删除或添加元素时,调用 Iterator 的remove() 方法是个安全的做法。
             */
        }
    }
  • 相关阅读:
    利刃 MVVMLight 1:MVVMLight介绍以及在项目中的使用
    HTML5项目笔记10:使用HTML5 IndexDB设计离线数据库
    MySQL数据库安装
    安装维护手册
    XXX银行项目部署
    使用Excel批量给数据添加单引号和逗号
    sublime3 快速创建html模板
    Wyn Enterprise 报表查询面板三种实现方法汇总
    仪表板中选项卡外观样式详细设置讲解
    Wyn Enterprise 自助式分析(1)门户中的个人偏好设置
  • 原文地址:https://www.cnblogs.com/lizhangyong/p/8884243.html
Copyright © 2020-2023  润新知