使用List集合时踩过的坑

1.使用Arrays.asList()声明集合

有时候我们在声明集合的时候喜欢使用Arrays.asList()方法,如下图所示:

 public static void main(String[] args) {
        List<String> lists = Arrays.asList("hello", "word");
        System.out.println(lists);
     
  }

但是有时候不注意的话,会踩到坑(比如我.....)。咋一看,以上代码好像没啥问题(不报错,也能运行成功)。接着往下看,当我们用试图修改他的值时,问题就来了。

添加元素后:

  public static void main(String[] args) {
        List<String> lists = Arrays.asList("hello", "word");
        System.out.println(lists);
      
        lists.add("!");
        System.out.println(lists);

    }

输出结果:

“不对啊,为什么改变元素之后就会报错呢?”我相信很多小伙伴肯定和当时的我有一样的疑问。当你点进Arrays的源码进去看的时候,你会发现。。。他虽然也继承了AbstractList类,但是这里面没有重写add和其他修改方法, Arrays.asList 体现的是适配器模式,只是一个转换接口,后台数据还是数组。换句话说,这样声明的集合是个只读集合。

所以正确的方法是:

 public static void main(String[] args) {
        List<String> lists = new ArrayList<>(Arrays.asList("hello", "word"));
        System.out.println(lists);

        lists.add("!");
        System.out.println(lists);

        //或者:
        List<String> list = new ArrayList<String>() {{
            add("hello");
            add("word");
        }};
        System.out.println(list);

        list.add("!");
        System.out.println(list);

    }

2.使用ArrayList的subList的注意事项

先说它的用法,subList意在取出集合中开始下标(包含)到结尾下标(不包含)的一段作为集合返回结果。

public static void main(String[] args) {
        List<String> nameList = new ArrayList<>();
        nameList.add("小明");
        nameList.add("小红");
        nameList.add("小白");
        nameList.add("小黑");
        nameList.add("我是真的没有拼多多");
        //注意:因为结尾下标不包含其中,所以实际取值取到最后一个的时候要等于集合长度!超过这个长度就会报错!
        List<String> nameList2 = nameList.subList(2, 5);

        System.out.println(nameList);
        System.out.println(nameList2);

    }

输出结果:

1. 修改原集合元素的值,会影响子集合;

 public static void main(String[] args) {
        List<String> nameList = new ArrayList<>();
        nameList.add("小明");
        nameList.add("小红");
        nameList.add("小白");
        nameList.add("小黑");
        nameList.add("我是真的没有拼多多");

        nameList.set(2,"小蓝");

        List<String> nameList2 = nameList.subList(2, 5);


        System.out.println(nameList);
        System.out.println(nameList2);

    }

输出结果:


2、 修改原集合的结构,会引起ConcurrentModificationException异常;

 List<String> nameList = new ArrayList<>();
        nameList.add("小明");
        nameList.add("小红");
        nameList.add("小白");
        nameList.add("小黑");
        nameList.add("我是真的没有拼多多");
        
        List<String> nameList2 = nameList.subList(2, 5);

        nameList.remove(2);

        System.out.println(nameList);
        System.out.println(nameList2);

报错:


3、 修改子集合元素的值,会影响原集合;

  public static void main(String[] args) {
        List<String> nameList = new ArrayList<>();
        nameList.add("小明");
        nameList.add("小红");
        nameList.add("小白");
        nameList.add("小黑");
        nameList.add("我是真的没有拼多多");

        List<String> nameList2 = nameList.subList(2, 5);

        nameList2.add("小蓝");
        System.out.println(nameList);
        System.out.println(nameList2);

    }

运行结果:


 

那看到这儿,我相信有些小伙伴就猜到了,“这两个集合该不会是引用的同一个内存地址吧?”我的回答是:是的,nameListnameList2 引用的是同一个内存地址。在 Java 中,subList 返回的是原始列表的视图,而不是独立的副本。因此,对其中一个列表的修改会影响到另一个列表。

在以上的示例中,nameList2 是通过 nameList.subList(2, 5) 创建的,它实际上是 nameList 的一个子列表,指向相同的数据。任何对 nameList2 的修改都将反映在 nameList 中,反之亦然。

翻开源代码你不难发现,他引用的都是在原来集合的基础上进行操作的,他并没有重新创建一个新的集合。

所以,当我们要想使用subList去定义一个新的集合的时候就要注意!千万不要直接用直接拿list接收,正确的做法是:

 public static void main(String[] args) {
        List<String> nameList = new ArrayList<>();
        nameList.add("小明");
        nameList.add("小红");
        nameList.add("小白");
        nameList.add("小黑");
        nameList.add("我是真的没有拼多多");

        List<String> nameList2 = new ArrayList<>( nameList.subList(2, 5));

        nameList2.add("小蓝");
        System.out.println(nameList);
        System.out.println(nameList2);

    }

3.在for里移除集合中的元素

ConcurrentModificationException: 如果在遍历集合的过程中修改了集合的结构(例如添加或删除元素),可能会导致 ConcurrentModificationException 异常。这是因为 Java 的集合类通常不支持在迭代过程中的结构性修改。

List<String> list = new ArrayList<>(Arrays.asList("one", "two", "three", "four"));

for (String element : list) {
    if (element.equals("two")) {
        // 在迭代过程中尝试删除元素,可能导致异常
        list.remove(element);
    }
}

解决方法:

  • 使用迭代器进行遍历,并使用迭代器的 remove 方法来安全地移除元素。
    List<String> list = new ArrayList<>(Arrays.asList("one", "two", "three", "four"));
    Iterator<String> iterator = list.iterator();
    
    while (iterator.hasNext()) {
        String element = iterator.next();
        if (element.equals("two")) {
            iterator.remove();
        }
    }
    

IndexOutOfBoundsException: 如果在 for 循环中通过索引遍历并删除元素,需要确保索引的有效性。如果索引越界,将抛出 IndexOutOfBoundsException

List<String> list = new ArrayList<>(Arrays.asList("one", "two", "three", "four"));

for (int i = 0; i < list.size(); i++) {
    // 如果在这里移除元素,可能导致索引越界异常
    list.remove(i);
}

解决方法:

  • 从后向前遍历,或者使用迭代器。
List<String> list = new ArrayList<>(Arrays.asList("one", "two", "three", "four"));

for (int i = list.size() - 1; i >= 0; i--) {
    // 从后向前遍历安全地移除元素
    list.remove(i);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值