1、应用 Arrays.asList 的注意事项
先来看下 Arrays.asList 的应用:
List<Integer> statusList = Arrays.asList(1, 2);
System.out.println(statusList);
System.out.println(statusList.contains(1));
System.out.println(statusList.contains(3));
// 输入
[1,2]
true
false // 因为这个汇合里没有值为 3 的这个元素,所以返回 false
而后,往 statusList 中增加元素 3,如下所示:
statusList.add(3);
System.out.println(statusList.contains(3));
预期的后果,应该是输入 true,然而理论却是抛出了 java.lang.UnsupportedOperationException
异样:
起因剖析
咱们看下 Arrays 类提供的静态方法 asList 的源码:
返回的是 ArrayList,然而此 ArrayList 并非彼 ArrayList,咱们平时应用位于 java.util 包下的 ArrayList
,
而此处的 ArrayList 却是 Arrays
类的外部类,它也继承了 AbstractList 类,重写了很多办法,比方咱们下面应用的 contains 办法,但并没有实现汇合的批改办法(add/remove/clear)。
所以在调用 add 办法时才会抛出 java.lang.UnsupportedOperationException
异样。
Arrays.asList 提现的是适配器模式,只是转换接口,后盾的数据仍是数组。
总结 Arrays.asList
办法能够在一些简略的场合应用,比方疾速申明一个汇合,判断某个值是否在容许的范畴内:
2、应用 ArrayList 的 subList 的注意事项
先来看下 subList 的简略应用:
List<String> bookList = new ArrayList<>();
bookList.add("边远的救世主");
bookList.add("背离");
bookList.add("天幕红尘");
bookList.add("人生");
bookList.add("平庸的世界");
List<String> luyaoBookList = bookList.subList(3, 5);
System.out.println(bookList);
System.out.println(luyaoBookList);
运行后果如下图所示:
从运行后果能够看出,subList 返回的是 bookList 中索引从 fromIndex(蕴含)到 toIndex(不蕴含)的元素汇合。
应用起来很简略,也很好了解,不过还是有以下几点要留神,否则会造成程序谬误或者异样:
- 批改原汇合元素的值,会影响子集合
- 批改原汇合的构造,会引起 ConcurrentModificationException 异样
- 批改子集合元素的值,会影响原汇合
- 批改子集合的构造,会影响原汇合
2.1 批改原汇合的值,会影响子集合(同时被批改)
比方,咱们批改下原汇合 bookList 中某一元素的值(非结构性批改):
// 批改 bookList 第三个元素值
bookList.set(3,"路遥一人生");
// 再输入 luyaoBookList 值
[路遥一人生, 平庸的世界]
能够看出,尽管咱们只是批改了原汇合 bookList 的值,然而影响到了子集合 luyaoBookList。
2.2 批改原汇合的构造,会引起 ConcurrentModificationException 异样
比方,咱们往原汇合 bookList 中增加一个元素(结构性批改):
// 往原汇合中增加元素
bookList.add("晚上从中午开始");
System.out.println(bookList);
System.out.println(luyaoBookList);
能够看出,当咱们往原汇合中增加了元素(结构性批改)后,在遍历子集合时,产生了 ConcurrentModificationException
异样。
注意事项:以上异样并不是在增加元素时产生的,而是在增加元素后,遍历子集合时产生的。
对于这一点,在《阿里巴巴 Java 开发手册》泰山版中是这样形容的:
在 subList 场景中,高度留神对父汇合元素的减少和删除,均会导致子列表的遍历,减少、删除产生 ConCurrentModlficationException 异样。
2.3、批改子集合元素的值,会影响原汇合
比方,咱们批改下子集合 luyaoBookList 中某一元素的值(非结构性批改):
// 批改子集合的值
List<String> luyaoBookList = bookList.subList(3, 5);
luyaoBookList.set(1,"路遥 - 平庸的世界");
// 批改了子集合的第二个元素值,同时父汇合的最初一个元素值也被批改
//bookList:[边远的救世王,背离,天幕红尘,人生,路遥 - 平庸的世界]
//luyaoBookList:[人生,平庸的世界]
能够看出,尽管咱们只是批改了子集合 luyaoBookList 的值,然而影响到了原汇合 bookList。
2.4、批改子集合的构造,会影响原汇合
比方,咱们往子集合 luyaoBookList 中增加一个元素(结构性批改):
List<String> bookList = new ArrayList<>();
bookList.add("边远的救世主");
bookList.add("背离");
bookList.add("天幕红尘");
bookList.add("人生");
bookList.add("平庸的世界");
List<String> luyaoBookList = bookList.subList(3, 5);
System.out.println(bookList);
System.out.println(luyaoBookList);
// 往子集合中增加元素
luyaoBookList.add("晚上从中午开始");
System.out.println(bookList);
System.out.println(luyaoBookList);
运行后果如下所示:
能够看出,当咱们往子集合中增加了元素(结构性批改)后,影响到了原汇合 bookList。
2.5 起因剖析
首先,咱们看下 subList 办法的正文,理解下它的用处:
Returns a view of the portion of this list between the specified {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
译文:
返回指定的 {@code fromIndex}(蕴含) 和{@code toIndex}(排除)之间的列表局部的视图
而后,咱们看下它的源码:
public List<E> subList(int fromIndex, int toIndex) {subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
能够看到,它调用了 SubList 类的构造函数,该构造函数的源码如下图所示:
能够看出,SubList 类是 ArrayList 的外部类,该构造函数中也并没有从新创立一个新的 ArrayList,所以批改原汇合或者子集合的元素的值,是会相互影响的。
2.6 总结
ArrayList 的 subList 办法,返回的是原汇合的一个子集合(视图),非结构性批改任意一个汇合的元素的值,都会彼此影响,结构性批改原汇合时,会报ConcurrentModificationException
异样,结构性批改子集合时,会影响原汇合,所以应用时要留神,防止程序谬误或者异样。