为什么要慎用List.subList()

此篇讲解为什么要慎用List.subList(),拆分集合应该使用什么方式

一、我们先添加一组个集合,然后使用subList拆分出一个集合

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("list==1");
        list.add("list==2");
        list.add("list==3");
        list.add("list==4");
        list.add("list==5");

        System.out.println("list:" + list);

        List<String> subList = list.subList(2, 4);
        System.out.println("subList:" + subList);
    }

subList从第二位开始截取,截取到第四位,来看一下subList的值

似乎一切正常!那么我们在subList之后将list的值修改,看结果

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("list==1");
        list.add("list==2");
        list.add("list==3");
        list.add("list==4");
        list.add("list==5");
        System.out.println("list:" + list);
        List<String> subList = list.subList(2, 4);
        list.set(2, "list==3==update");
        System.out.println("subList:" + subList);
    }

我们在subList之后将list中下标为2的数据(第三个)修改为:"list==3==update",常理来说此时subList已经是一个新集合,没有改动数据应该不会发生变化,但是结果中却显示subList的值也发生了变化。

原因:subList() 方法返回的是原列表的一个视图,而不是一个独立的副本。这意味着对原列表的修改会反映到子列表中,因为它们共享同一份数据存储。

所以执行 list.set(2, "list==3==update"); 这行代码时,实际上是改变了原列表在索引2位置的值,而这个改变同样会影响到基于原列表创建的子列表 subList

为了证实这一点,我们再修改sunList的值

        List<String> list = new ArrayList<>();
        list.add("list==1");
        list.add("list==2");
        list.add("list==3");
        list.add("list==4");
        list.add("list==5");
        List<String> subList = list.subList(2, 4);
        subList.add("list==5==subList");
        System.out.println("list:" + list);
        System.out.println("subList:" + subList);

可以看出list的值也被修改

看一下ArrayList中的subList方法

可以看出来,ArrayList的subList方法返回了SubList类,SubList这个类最终也实现了List接口

还有如果subList的toIndex超出了原list的大小会抛出IndexOutOfBoundsException异常

最后如果要拆分list尽量使用Stream处理

        // skip:过2个元素、limit:取2个元素
        List<String> skipList = list.stream().skip(2).limit(10).collect(Collectors.toList());