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);
}
运行结果:
那看到这儿,我相信有些小伙伴就猜到了,“这两个集合该不会是引用的同一个内存地址吧?”我的回答是:是的,nameList
和 nameList2
引用的是同一个内存地址。在 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);
}