在 Java 中使用 ArrayList 的 13 个技巧

在上一篇文章中我们已经看到了 10 个在 Java 中使用 ArrayList 的示例,从创建实例到填充 ArrayList、搜索、排序和检索元素,现在是时候重新审视 Java 中 ArrayList 的一些重要属性,并学习一些在 Java 中有效使用 ArrayList 的技巧了。

1、 ArrayList 不是同步集合,不适合多线程间并发使用。 如果你想在多线程环境中使用类似 ArrayList 的数据结构,那么你需要使用新的 CopyonWriteArrayList 或使用 Collections.synchronizedList() 创建同步列表。

前者是并发收集包的一部分,比第二个更具可扩展性,但只有在有很多读者而只有少数人写的时候才有用。 由于每次写入时都会创建 ArrayList 的新副本,因此如果在写入密集型环境中使用它可能会过大。

第二种选择是严格同步的集合,很像 Vector 或 Hashtable,但它不可扩展,因为一旦线程数量急剧增加,竞争就会成为一个大问题。

2、 CopyOnWriteArrayList 建议用于并发多线程环境,因为它针对多个并发读取进行了优化,并为写入操作创建副本。 这是在 Tiger,又名 JDK 1.5 中添加的。 它是 java.util.concurrent 包的一部分,还有 ConcurrentHashMap 和 BlockingQueue

3、 当 ArrayList 变满时,它会创建另一个数组并使用 System.arrayCopy() 将所有元素从一个数组复制到另一个数组。 这是插入需要花费大量时间的地方。

4、 Java ArrayList 的 Iterator 和 ListIterator 是 fail-fast 这意味着如果 ArrayList 在创建 Iterator 后的任何时候在结构上被修改,除了通过迭代器自己的 remove 或 add 方法以外的任何方式,Iterator 都会抛出ConcurrentModificationException。 因此,面对并发修改,Iterator 会快速干净地失败,这就是它被称为 fail-fast 的原因。

5、 ConcurrentModificationException 不保证,它只是尽最大努力抛出。

6、 如果我们正在创建同步列表,建议在创建底层 ArrayList 的实例时创建,以防止意外地对列表进行非同步访问。

7、 应用程序可以在使用 ensureCapacity() 操作添加大量元素之前增加 ArrayList 实例的容量。 这可能会减少由于 ArrayList 的增量填充而导致的增量重新分配量。

8、 size() , isEmpty() , get() , set() , iterator() , listIterator() 操作在恒定时间内运行,因为 ArrayList 是基于 Array 但添加或删除元素与 LinkedList 相比成本高 .

9、 ArrayList 类在 Java 1.5 中得到了增强,以支持在 ArrayList 上添加额外类型安全的泛型。 建议使用 ArrayList 的泛型版本,以确保您的 ArrayList 仅包含指定类型的元素并避免任何 ClassCastException。

10、 由于 ArrayList 实现了 List 接口,它维护元素的插入顺序并允许重复。

11、 如果我们在 Java 中将 ArrayList 引用设置为 null,则 ArrayList 的所有元素都可以在 Java 中进行垃圾回收,前提是这些对象不再存在强引用。

12、 始终使用 isEmpty() 方法检查 ArrayList 是否为空,而不是使用 size() == 0 检查。 前者可读性强很多,如下代码所示

if (!listOfItems.isEmpty()) {
    System.out.println("Starting order processing");
}
if (listOfOrders.size() != 0) {
    System.out.println("Order processing started");
}

13、 从 Java 5 Tiger 开始,ArrayList 被参数化,我们应该始终使用此类的通用版本。 这可以防止在水果列表中插入鱼或在卡片列表中插入骰子的经典错误。 当我们使用泛型时,这些错误将被编译器捕获。

因此,它还可以在运行时防止 ClassCastException,因为编译器会确保从 Collection 中存储和检索正确类型的对象。 它还消除了手动转换的需要,因为 Java 编译器会自动添加隐式转换。

对于初学者来说,理解泛型有点棘手,但值得学习,因为现在没有人使用没有泛型的集合。