使用List容易犯下的几个常见错误(经验教训)

新手都容易犯这个错误,先看代码:

        List<String> list = new ArrayList<String>();
        
        for(int i=0;i<list.size();i++){
            System.err.println(list.get(i).toString());
        }
        if(list!=null){
            System.out.println("不为空");
        }else{
            System.out.println("为空,需进行赋值判断");
        }

13566833-50c56559204b81f9.png

改代码如下:

        if(!list.isEmpty()){
            System.out.println("不为空");
        }else{
            System.out.println("为空,需进行赋值判断");
        }

改成以上代码,ok了!这个错误就是对集合判断是否为Null出错,需要加上list.size()>0或者使用才可以list.isEmpty()才行。
List list=new ArrayList();
这样的list其实不为null,但是判断size的时候,实则是为0,所以判断集合的时候,一定记得要双重判断。即list!=null && list.size()>0才好。
PS:list.isEmpty()和list.size()==0 没有区别, isEmpty()判断有没有元素,而size()返回有几个元素,如果判断一个集合有无元素,建议用isEmpty()方法,该方法简单、清晰明了!

public class ListGu {
    
    private static List<String> list;
    
    public static void main(String[] args) {
        setList();
    }
    
    //对集合重新赋值
    private static void setList() {
        for(int i=0;i<10;i++){
            list.add(String.valueOf(i));
        }
        
        for(int i=0;i<list.size();i++){
            System.err.println(list.get(i).toString());
        }
    }   
}

上面的代码乍一看,没毛病,可是一运行:

13566833-ba16863aced3a278.png

按住ctrl键,点List进去看底层源码:

13566833-f3cf59ac782e1d08.png

擦,竟然是个接口,竟然没new对象就直接赋值。发现问题,及时改正:

public class ListGu {
    
    private static List<String> list;
    
    public static void main(String[] args) {
        setList();
    }
    //对集合重新赋值
    private static void setList() {
        for(int i=0;i<10;i++){
            list = new ArrayList<String>();  //new对象
            list.add(String.valueOf(i));
        }
        
        for(int i=0;i<list.size();i++){
            System.err.println(list.get(i).toString());
        }
    }
}

运行代码,竟然不是预想中的结果:

13566833-6424afbdcb94ff7b.png

这是为什么呢?现在我们知道,使用List时,需要new对象,仔细一看,擦,竟然在循环里new对象,这种错误,特别容易犯!!

public static void main(String[] args) {
        List<List<String>> list=new ArrayList<>();

        List<String> list2=new ArrayList<>();
        for(int i=0;i<10;i++){
            list2.add(""+i);    
            list.add(list2);
            list2.clear();
        }
        // 遍历List
        for(int i=0;i<list.size();i++){
            System.err.println(list.get(i).toString());
        }
    }

乍一看以上代码,没毛病,很简单的逻辑,少new一个对象,可以达到节省优化代码,节省虚拟机内存,可是一运行,擦,竟然是这样的结果:

13566833-6af21aae9a785f65.png

这个错误引起就是因为list中存储的是对象的引用,而不是对象本身。如果不清楚这一点,会常踩这个坑。该代码虽然可以达到一个对象重复使用的效果,但是因为list存储的是对象的引用,所以当list2.clear()的时候,list中的list2也会clear,这样最后得到的就只能是一堆空的集合。

Array转ArrayList(常见错误补充)

当需要把Array转成ArrayList的时候,我们经常这样做:
List<String> list = Arrays.asList(arr);

假若这个时候我们需要在list上添加删除一些东西:

public static void main(String[] args) {
        String[] array = { "java", "c" };
        List<String> list = Arrays.asList(array);
        
        for (String list2 : list) {
            System.err.println(list2.toString());
        }
        
        list.add("我是李逍遥");
        list.add("我是林月如");
        list.remove("c");
        for (String list2 : list) {
            System.err.println(list2.toString());
        }
        
    }

竟然执行失败??

13566833-32f792065d8d1224.jpg

需要注意的是:
Arrays.asList()的确会返回一个ArrayList,但是要特别注意,这个ArrayList是Arrays类的静态内部类,并不是java.util.ArrayList类。

java.util.Arrays.ArrayList类实现了set(), get(),contains()方法,但是并没有实现增加元素的方法(事实上是可以调用add方法,但是没有具体实现,仅仅抛出UnsupportedOperationException异常),因此它的大小也是固定不变的。为了创建一个真正的java.util.ArrayList,你应该这样做:

ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));
ArrayList的构造方法可以接收一个Collection类型,而java.util.Arrays.ArrayList已经实现了该接口。

public static void main(String[] args) {
        String[] array = { "java", "c" };
//      List<String> list = Arrays.asList(array);
//      for (String list2 : list) {
//          System.err.println(list2.toString());
//      }
//      list.add("我是李逍遥");
//      list.add("我是林月如");
//      list.remove("c");
//      for (String list2 : list) {
//          System.err.println(list2.toString());
//      }
        
        ArrayList<String> list = new ArrayList<String>(Arrays.asList(array));
        for (String list2 : list) {
            System.err.println(list2.toString());
        }
        list.add("我是李逍遥");
        list.add("我是林月如");
        list.remove("c");
        System.out.println("----------------");
        for (String list2 : list) {
            System.err.println(list2.toString());
        }
    }

13566833-1d108da59dec4795.jpg

add成功,remove成功!!

删除List中的一个元素

删除list中的元素,肯定要循环,先看这段代码:

public static void main(String[] args) {
        ArrayList<String> list = 
        new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
        for (int i = 0; i < list.size(); i++) {
            list.remove(i);
        }
        System.out.println(list);
    }

结果打印: [b, d]

这个时候,肯定想到需要用迭代器,为什么循环删除list元素会导致这种错误呢?这是因为:当一个元素被删除的时候,list大小减小,然后原先索引指向了其它元素,所以如果你想在循环里通过索引来删除多个元素,将不会正确工作,如果你用foreach循环代替迭代器,代码还是执行失败,如下代码:

public static void main(String[] args) {
//      ArrayList<String> list = new 
//
//      ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
//      System.err.println(list);
//      
//      for (int i = 0; i < list.size(); i++) {
//          list.remove(i);
//      }
//      System.out.println(list);
        
        ArrayList<String> list = new

        ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
        
        for (String s : list) {

            if (s.equals("a"))
                list.remove(s);
        }
    }

执行结果:
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    at java.util.ArrayList$Itr.next(ArrayList.java:851)
    at com.kai.Array.main(Array.java:22)

所以,移除list元素,我们一定要用迭代器:

public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));

        Iterator<String> iter = list.iterator();
        while (iter.hasNext()) {

            String s = iter.next();

            if (s.equals("a")) {
                iter.remove();
            }
        }
        System.err.println(list);
    }

执行打印:[b, c, d]
next()方法需要在remove()方法之前被调用,在foreach循环里,编译器会在删除元素操作化调用next方法,这导致了ConcurrentModificationException异常。更多详细信息,可以查看ArrayList.iterator()的源码。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值