在创建集合时指定一个合适的初始容量可以显著减少扩容的次数,从而提高性能。以下是一些常见集合类型的建议和示例代码,帮助你在创建集合时指定合适的初始容量。
1. ArrayList
- 建议:如果你预计集合将存储大量元素,可以在创建
ArrayList
时指定一个较大的初始容量。例如,如果你知道集合最终将包含1000个元素,可以将初始容量设置为1000或稍大一些。 - 示例代码:
import java.util.ArrayList; public class ArrayListExample { public static void main(String[] args) { int initialCapacity = 1000; // 预计的元素数量 ArrayList<String> list = new ArrayList<>(initialCapacity); for (int i = 0; i < 1000; i++) { list.add("Element " + i); } System.out.println("List size: " + list.size()); } }
2. HashMap
- 建议:对于
HashMap
,初始容量和负载因子是两个重要的参数。初始容量应设置为预期元素数量除以负载因子(默认为0.75),并向上取整到最近的2的幂次方。例如,如果你预计集合将包含1000个键值对,可以将初始容量设置为1000 / 0.75 ≈ 1334,然后取最近的2的幂次方1024。 - 示例代码:
import java.util.HashMap; public class HashMapExample { public static void main(String[] args) { int expectedSize = 1000; // 预计的键值对数量 float loadFactor = 0.75f; // 默认负载因子 int initialCapacity = (int) Math.ceil(expectedSize / loadFactor); initialCapacity = Integer.highestOneBit(initialCapacity - 1) << 1; // 取最近的2的幂次方 HashMap<String, String> map = new HashMap<>(initialCapacity); for (int i = 0; i < 1000; i++) { map.put("Key " + i, "Value " + i); } System.out.println("Map size: " + map.size()); } }
3. HashSet
- 建议:
HashSet
内部使用HashMap
,因此其初始容量的计算方法与HashMap
相同。如果你预计集合将包含1000个元素,可以将初始容量设置为1000 / 0.75 ≈ 1334,然后取最近的2的幂次方1024。 - 示例代码:
import java.util.HashSet; public class HashSetExample { public static void main(String[] args) { int expectedSize = 1000; // 预计的元素数量 float loadFactor = 0.75f; // 默认负载因子 int initialCapacity = (int) Math.ceil(expectedSize / loadFactor); initialCapacity = Integer.highestOneBit(initialCapacity - 1) << 1; // 取最近的2的幂次方 HashSet<String> set = new HashSet<>(initialCapacity); for (int i = 0; i < 1000; i++) { set.add("Element " + i); } System.out.println("Set size: " + set.size()); } }
4. Vector
- 建议:
Vector
与ArrayList
类似,但默认情况下新容量是旧容量的两倍。你可以根据预期的元素数量来设置初始容量。例如,如果你预计集合将包含1000个元素,可以将初始容量设置为1000。 - 示例代码:
import java.util.Vector; public class VectorExample { public static void main(String[] args) { int initialCapacity = 1000; // 预计的元素数量 Vector<String> vector = new Vector<>(initialCapacity); for (int i = 0; i < 1000; i++) { vector.add("Element " + i); } System.out.println("Vector size: " + vector.size()); } }
5. ConcurrentHashMap
- 建议:
ConcurrentHashMap
的初始容量和负载因子的计算方法与HashMap
相同。此外,还可以指定并发级别(concurrency level),这会影响内部段的数量。如果你预计集合将包含1000个键值对,可以将初始容量设置为1000 / 0.75 ≈ 1334,然后取最近的2的幂次方1024。 - 示例代码:
import java.util.concurrent.ConcurrentHashMap; public class ConcurrentHashMapExample { public static void main(String[] args) { int expectedSize = 1000; // 预计的键值对数量 float loadFactor = 0.75f; // 默认负载因子 int initialCapacity = (int) Math.ceil(expectedSize / loadFactor); initialCapacity = Integer.highestOneBit(initialCapacity - 1) << 1; // 取最近的2的幂次方 int concurrencyLevel = 16; // 并发级别 ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>(initialCapacity, loadFactor, concurrencyLevel); for (int i = 0; i < 1000; i++) { map.put("Key " + i, "Value " + i); } System.out.println("Map size: " + map.size()); } }
6. CopyOnWriteArrayList
- 建议:
CopyOnWriteArrayList
在每次修改时都会创建一个新的数组副本,因此初始容量的设置尤为重要。如果你预计集合将包含1000个元素,可以将初始容量设置为1000。 - 示例代码:
import java.util.concurrent.CopyOnWriteArrayList; public class CopyOnWriteArrayListExample { public static void main(String[] args) { int initialCapacity = 1000; // 预计的元素数量 CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(new String[initialCapacity]); for (int i = 0; i < 1000; i++) { list.add("Element " + i); } System.out.println("List size: " + list.size()); } }
7. CopyOnWriteArraySet
- 建议:
CopyOnWriteArraySet
内部使用CopyOnWriteArrayList
,因此其初始容量的设置方法与CopyOnWriteArrayList
相同。如果你预计集合将包含1000个元素,可以将初始容量设置为1000。 - 示例代码:
import java.util.concurrent.CopyOnWriteArraySet; public class CopyOnWriteArraySetExample { public static void main(String[] args) { int initialCapacity = 1000; // 预计的元素数量 CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>(new String[initialCapacity]); for (int i = 0; i < 1000; i++) { set.add("Element " + i); } System.out.println("Set size: " + set.size()); } }
总结
- 基于数组的集合(如
ArrayList
、Vector
、CopyOnWriteArrayList
)可以通过指定初始容量来减少扩容次数。 - 基于哈希表的集合(如
HashMap
、HashSet
、ConcurrentHashMap
)需要考虑负载因子,并将初始容量设置为预期元素数量除以负载因子,再取最近的2的幂次方。 - 基于链表或树的集合(如
LinkedList
、TreeSet
)不需要指定初始容量,因为它们是动态扩展的。
通过合理设置初始容量,可以显著减少集合的扩容次数,提高程序的性能。特别是对于大型数据集和高性能要求的应用,这一点尤为重要。