ArrayList非线程安全,多线程下可用Collections.synchronizedList或CopyOnWriteArrayList;遍历时避免直接修改集合以防ConcurrentModificationException,推荐增强for循环或迭代器遍历,删除操作应使用迭代器remove或倒序遍历。

ArrayList,这个Java集合框架里的“常客”,本质上就是一个动态数组。它提供了一种灵活的方式来存储和操作对象序列,可以根据需要自动扩容,免去了我们手动管理数组大小的麻烦。它的常用操作主要围绕着元素的增、删、改、查,以及一些辅助性的管理方法。
ArrayList的核心操作无非就是围绕着它内部那个可变大小的数组来展开。我们往里塞东西,用
add()
get()
set()
remove()
size()
isEmpty()
contains()
说到ArrayList,我个人在使用中遇到最多的“坑”之一,就是在多线程场景下。ArrayList它本身不是线程安全的,这一点非常关键。这意味着,如果你在多个线程中同时对一个ArrayList进行修改(比如一个线程在添加,另一个线程在删除),或者一个线程在遍历而另一个线程在修改,很大概率会遇到
ConcurrentModificationException
那么,怎么解决呢? 一种常见的做法是使用
Collections.synchronizedList()
List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());
synchronizedList.add("item1");
// ... 其他操作这种方式会在每次操作时自动加锁,确保了操作的原子性。但它的粒度比较粗,每次操作都锁住整个列表,在高并发场景下可能会成为性能瓶颈。
另一种更“现代”的选择是使用
java.util.concurrent
CopyOnWriteArrayList
CopyOnWriteArrayList
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.List;
List<String> copyOnWriteList = new CopyOnWriteArrayList<>();
copyOnWriteList.add("itemA");
// 读操作可以并发进行,不会抛异常
for (String item : copyOnWriteList) {
System.out.println(item);
}我通常会根据具体的业务场景来选择。如果并发修改不频繁,或者对性能要求没那么极致,
Collections.synchronizedList()
CopyOnWriteArrayList
这三者都是
List
ArrayList:
get(index)
LinkedList:
get(index)
Vector:
java.util.concurrent
Collections.synchronizedList()
CopyOnWriteArrayList
简单来说,如果你需要快速查找,用ArrayList;如果你需要频繁增删,用LinkedList。Vector嘛,现在基本不太推荐用了。
遍历ArrayList,看似简单,实则也有一些门道和陷阱。我通常会根据具体需求和场景来选择遍历方式。
1. 增强for循环 (for-each loop): 这是我最常用的一种方式,代码简洁,可读性高。
List<String> names = new ArrayList<>(Arrays.asList("Alice", "Bob", "Charlie"));
for (String name : names) {
System.out.println(name);
}优点: 代码简洁,不易出错。 缺点: 无法获取元素的索引;在遍历过程中不能修改集合(会抛
ConcurrentModificationException
2. 传统for循环: 当你需要访问元素的索引时,这种方式是首选。
List<String> names = new ArrayList<>(Arrays.asList("Alice", "Bob", "Charlie"));
for (int i = 0; i < names.size(); i++) {
System.out.println("Index " + i + ": " + names.get(i));
}优点: 可以获取元素的索引;在遍历过程中可以安全地修改集合(但要小心索引的变化)。 缺点: 代码相对不那么简洁;如果
names.get(i)
get(i)
get(i)
3. 使用Iterator迭代器: 这是Java集合框架推荐的通用遍历方式,也是在遍历过程中安全移除元素的唯一方式。
import java.util.Iterator;
import java.util.ArrayList;
import java.util.List;
List<String> names = new ArrayList<>(Arrays.asList("Alice", "Bob", "Charlie", "David"));
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String name = it.next();
System.out.println(name);
if ("Bob".equals(name)) {
it.remove(); // 安全移除元素
}
}
System.out.println("After removal: " + names);优点: 可以在遍历过程中安全地移除元素(通过
it.remove()
Iterable
Iterator.remove()
add()
remove()
ConcurrentModificationException
遍历时的陷阱:
ConcurrentModificationException
add()
remove()
Iterator
remove()
// 错误示例:会抛出ConcurrentModificationException
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
for (String s : list) {
if ("B".equals(s)) {
list.remove(s); // 危险!
}
}倒序遍历以安全删除: 如果你必须在传统for循环中删除元素,一种常见的技巧是倒序遍历。
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
for (int i = list.size() - 1; i >= 0; i--) {
if ("B".equals(list.get(i))) {
list.remove(i); // 安全!
}
}这样,即使删除元素,也不会影响到前面已经遍历过的元素的索引。
性能考量: 对于ArrayList,传统for循环的
get(i)
get(i)
选择合适的遍历方式,不仅能让代码更健壮,也能在特定场景下提升性能。通常我推荐优先使用增强for循环,如果需要索引或在遍历时安全删除,再考虑传统for循环或迭代器。
以上就是ArrayList常用操作方法详解的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号