一起来愉快的踩坑之旅——List

一起来愉快的踩坑之旅——List

​ 由于在平时编程中常用到List,但是List里面还有很多不为人知的坑,下面就来总结下常见的一些坑

Arrays$ArrayList到底你是谁

问题代码
 public static void main(String[] args) {
        String[] arrays ={"1","2","3"};
        List<String> list = Arrays.asList(arrays);
        list.add("4");
    }
分析

​ 看似很简单的代码,使用Arrays.asList将一个数组转化为List然后再添加一个元素,十分正常但是会抛出异常如下:

​ 为啥我返回的ArrayList添加一个元素会报错?决定Debug进去看一下:

​ 原来用Arrays.aslist得到的不是一个ArrayList而是一个Arrays的一个内部类

​ add和remove方法实际都来自AbstractList而java.utilArrays$ArrayList并没有重写父类的方法,而会抛出UnsupportedOperationException。这就是为啥不支持增删的原因。

java.util.Arrays A r r a y L i s t ( ArrayList ( ArrayList表示内部类的意思,下面的源码是Arrays内部类*ArrayList 的类型定义源码,在**java.util.Arrays.class文件中***)

list互相影响?

​ 上面使用Arrays.asList(arrays)获取,除了不支持增删改查还会有一个大问题,就是原数组和新生成的内部数组会互相影响

 public static void main(String[] args) {
        String[] arrays ={"1","2","3"};
        List<String> list = Arrays.asList(arrays);
        list.set(0,"a");
        arrays[2] = "c";
        System.out.println("arrays:"+Arrays.toString(arrays));
        System.out.println("list"+list);
    }

结果:

​ 可以看到,不管是修改原数组还是新的list集合两者都会互相影响。

​ 是因为这个方法实现的时候使用了原始的数组

解决问题
  • 套娃一层ArrayList

    List<String> list = new ArrayList<>(Arrays.asList(arrays));
    

    但是十分的麻烦

  • 谷歌提供的Guava Lists 方法

    List<String> list = Lists.newArrayList(arrays);
    

​ 这两种方法都可以将新的List和原始数组解耦,不影响互相使用,同时由于生成的是正在的ArrayList,可以正常使用

​ 与Arrays.asList一样的subList方法产生的新集合也会和原始的List集合互相影响。由于SubList内部有一个parent字段保存了最原始的List。

​ 而且由于SubList还在引用原始的List所以容易造成OOM问题。由于每个SubList都会强引用一个10万个元素的原始List导致GC无法回收

foreach 增加/删除元素大坑

代码:

public static void main(String[] args) {
       String[] arrays = {"1","2","3"};
       List<String> list = new ArrayList<String>(Arrays.asList(arrays));
       for(String str:list){
           if (str.equals("1")){
               list.remove(str);
           }
       }
    }

​ 看似很正常,然是却报错

​ 可以清楚的看到程序的最终错误是由ArrayList$Itr.next处抛出,但是我们没有调用该方法,实际上是由于foreach这种方法是一种语法糖,其实际上就是Iterator迭代器实现方法。

解决方法
  • 使用Iterator 的remove方法删除元素

     public static void main(String[] args) {
           String[] arrays = {"1","2","3"};
           List<String> list = new ArrayList<String>(Arrays.asList(arrays));
           Iterator<String> iterator =list.iterator();
           while (iterator.hasNext()){
               String str = iterator.next();
               if("1".equals(str)){
                   iterator.remove();
               }
           }
            list.toString();
        }
    
  • JDK1.8 List removeIf

     public static void main(String[] args) {
           String[] arrays = {"1","2","3"};
           List<String> list = new ArrayList<String>(Arrays.asList(arrays));
           list.removeIf(str->str.equals("1"));
            System.out.println(list.toString());
        }
    

t(arrays));
list.removeIf(str->str.equals(“1”));
System.out.println(list.toString());
}





  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值