不是什么高深玩意,Arrays.asList、ArrayList.subList需要注意的坑

前言

集合是日常工作中几乎每天都在用的玩意,也是八股文中被翻烂的东西,诸如List、Map,确实很重要也很实用,但是不注意细节就比较容易踩坑。比较常见的就是今天要整理的Arrays.asList和ArrayList.subList。不是什么高深的东西,日常一整理。

最常用的写法

 List<Integer> list = new ArrayList<>();
 list.add(10);
 list.add(20);

使用Arrays.asList的注意事项

踩坑的大部分原因

图方便,有时候对于少量的几个元素,心想着这不是有现成的方法吗,好,梭哈

List<Integer> statusList = Arrays.asList(1, 2);

不好意思,这确实没少毛病。上线后一段时间,需要加n个元素,看到有集合,easy,好,在原来的基础上继续梭哈,代码变成这样

List<Integer> statusList = Arrays.asList(1, 2);
statusList.add(3);

上线后,boom!检查问题,还死鸭子嘴硬,这代码这么简单,肯定不是这个地方出错,看一下报错:

alt

原因分析

点进去,看一下Arrays类提供的静态方法asList的源码:

alt 细心一看,就会发现此ArrayList并不是我们经常使用的ArrayList,因为我们平时经常使用的ArrayList是位于java.util包下的:

alt 但是此处的ArrayList却是Arrays类的内部类,继续看看他的继承类,

alt 它也继承了AbstractList类,重写了很多方法,比如我们上面使用的contains方法,但是却没有重写add方法,所以我们在调用add方法时才会抛出java.lang.UnsupportedOperationException异常。

在《阿里巴巴Java开发手册》泰山版中,有说明这个注意点:

使用工具类 Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常。

alt

小结

简单场合可以使用Arrays.asList,比如快速声明一个集合,判断某个值是否在允许的范围内,但是不要调用他的修改方法,实在要用,先看看是否有重新对应的方法。

使用ArrayList的subList的注意事项

先看个Demo

List<String> bookList = new ArrayList<>();
bookList.add("天道");
bookList.add("倚天屠龙记");
bookList.add("阿甘正传");
bookList.add("你好,明天");
bookList.add("我是谁");

List<String> subBookList = bookList.subList(3, 5);
System.out.println(bookList);
System.out.println(subBookList);

执行结果如下:

alt

从运行结果可以看出,subList返回的是bookList中索引从fromIndex(包含)到toIndex(不包含)的元素集合。

使用起来很简单,主要有以下几点要注意,否则会造成程序错误或者异常:

  • 修改原集合元素的值,会影响子集合
  • 修改原集合的结构,会引起ConcurrentModificationException异常
  • 修改子集合元素的值,会影响原集合
  • 修改子集合的结构,会影响原集合 以上几点在《阿里巴巴Java开发手册》泰山版中是这样描述的:
alt

修改原集合的值,会影响子集合

如下验证:

alt

可以看出,虽然我们只是修改了原集合bookList的值,但是影响到了子集合subBookList

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

alt 温馨提醒:其实装好相关的插件,会自然提示可能出现的异常,可以整一下

修改子集合的值,会影响原集合

alt

修改子集合的结构,会影响原集合

alt

原因分析

看下subList方法的注释,了解下它的用途:

alt
  • 简单理解:返回指定的{@code fromIndex}(包含)和{@code toIndex}(排除)之间的列表部分的视图。 看下它的源码:
public List<E> subList(int fromIndex, int toIndex) {
    
    
    subListRangeCheck(fromIndex, toIndex, size);
    return new SubList(this, 0, fromIndex, toIndex);
}

它调用了SubList类的构造函数,该构造函数的源码如下图所示:

alt

可以看出,SubList类是ArrayList的内部类,该构造函数中也并没有重新创建一个新的ArrayList,所以修改原集合或者子集合的元素的值,是会相互影响的。

写在最后

好了,明白了是什么原因了吧。不要图方便,不看清他的原理。这里是"安前码后",一个分享实用内容的号,觉得用心整理的,帮忙给个三连。更多内容持续输出中。

本文由 mdnice 多平台发布

猜你喜欢

转载自blog.csdn.net/weixin_42329623/article/details/130396223