Java 集合,也叫作容器,主要是由两大接口派生而来:一个是 Collection接口,主要用于存放单一元素;另一个是 Map 接口,主要用于存放键值对。对于Collection 接口,下面又有三个主要的子接口:List Set Queue。
List
ArrayList
创建ArrayList
1 2 3
| ArrayList<String> list = new ArrayList<>(); ArrayList<Integer> listWithCapacity = new ArrayList<>(20); ArrayList<String> listFromOther = new ArrayList<>(otherList);
|
添加元素
1 2 3 4
| list.add("apple"); list.add(1, "banana"); list.addAll(otherList); list.addAll(2, otherList);
|
获取元素
1 2 3 4 5 6
| String fruit = list.get(0); boolean hasApple = list.contains("apple"); int index = list.indexOf("banana"); int lastIndex = list.lastIndexOf("banana"); int size = list.size(); boolean isEmpty = list.isEmpty();
|
修改元素
删除元素
1 2 3 4
| list.remove("apple"); list.remove(0); list.removeAll(otherList); list.clear();
|
与数组之间的切换
1 2 3
| List<String> sub = list.subList(1, 3); Object[] array = list.toArray(); String[] arr = list.toArray(new String[0]);
|
遍历方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); }
for (String s : list) { System.out.println(s); }
list.forEach(item -> System.out.println(item));
Iterator<String> it = list.iterator(); while (it.hasNext()) { System.out.println(it.next()); }
|
排序与替换
1 2 3 4 5
| Collections.sort(list); Collections.sort(list, Collections.reverseOrder()); Collections.reverse(list); Collections.shuffle(list); Collections.fill(list, "x");
|
线程安全处理
1
| List<String> syncList = Collections.synchronizedList(new ArrayList<>());
|
LinkedList
创建 LinkedList
1 2
| LinkedList<String> list = new LinkedList<>(); LinkedList<String> list2 = new LinkedList<>(otherCollection);
|
添加元素
1 2 3 4 5 6 7
| list.add("apple"); list.add(0, "banana"); list.addFirst("first"); list.addLast("last"); list.offer("offer"); list.offerFirst("offerFirst"); list.offerLast("offerLast");
|
访问元素
1 2 3 4 5 6
| String first = list.get(0); String first2 = list.getFirst(); String last = list.getLast(); String peek = list.peek(); String peekFirst = list.peekFirst(); String peekLast = list.peekLast();
|
修改元素
删除元素
1 2 3 4 5 6 7 8 9
| list.remove(); list.remove(0); list.remove("apple"); list.removeFirst(); list.removeLast(); list.poll(); list.pollFirst(); list.pollLast(); list.clear();
|
查找元素
1 2 3
| boolean has = list.contains("apple"); int index = list.indexOf("apple"); int lastIndex = list.lastIndexOf("apple");
|
遍历方法
1 2 3 4 5 6 7 8 9 10 11
| for (String s : list) { System.out.println(s); }
list.forEach(System.out::println);
Iterator<String> it = list.iterator(); while (it.hasNext()) { System.out.println(it.next()); }
|
与数组的转换
1 2 3
| Object[] array = list.toArray(); String[] arr = list.toArray(new String[0]); List<String> sub = list.subList(1, 3);
|
线程安全
1
| List<String> syncList = Collections.synchronizedList(new LinkedList<>());
|
Queue/Deque
Queue 接口 |
抛出异常 |
返回特殊值 |
| 插入队尾 |
add(E e) |
offer(E e) |
| 删除队首 |
remove() |
poll() |
| 查询队首元素 |
element() |
peek() |
Deque 接口 |
抛出异常 |
返回特殊值 |
| 插入队首 |
addFirst(E e) |
offerFirst(E e) |
| 插入队尾 |
addLast(E e) |
offerLast(E e) |
| 删除队首 |
removeFirst() |
pollFirst() |
| 删除队尾 |
removeLast() |
pollLast() |
| 查询队首元素 |
getFirst() |
peekFirst() |
| 查询队尾元素 |
getLast() |
peekLast() |
| 栈插入 |
push(E e)=addFirst(E e) |
|
| 栈删除 |
pop()=removeFirst() |
|
这两个接口的实现为ArrayDeque和LinkedList:
ArrayDeque 是基于可变长的数组和双指针来实现,而 LinkedList 则通过链表来实现。
ArrayDeque 不支持存储 NULL 数据,但 LinkedList 支持。
ArrayDeque 是在 JDK1.6 才被引入的,而LinkedList 早在 JDK1.2 时就已经存在。
ArrayDeque 插入时可能存在扩容过程, 不过均摊后的插入操作依然为 O(1)。虽然 LinkedList 不需要扩容,但是每次插入数据时均需要申请新的堆空间,均摊性能相比更慢。
Java中推荐使用ArrayDeque作为队列和栈的实现类。
“ArrayDeque is likely to be faster than Stack when used as a stack, and faster than LinkedList when used as a queue.”
—— 来自 ArrayDeque 的官方 Javadoc
ArrayDeque
| 类型 |
方法 |
说明 |
| 添加 |
addFirst(E e) |
从队头插入 |
| 添加 |
addLast(E e) / add(E e) |
从队尾插入 |
| 移除 |
removeFirst() / pollFirst() |
移除并返回队头元素 |
| 移除 |
removeLast() / pollLast() |
移除并返回队尾元素 |
| 访问 |
getFirst() / peekFirst() |
查看队头元素但不移除 |
| 访问 |
getLast() / peekLast() |
查看队尾元素但不移除 |
| 栈操作 |
push(E e) |
相当于 addFirst |
| 栈操作 |
pop() |
相当于 removeFirst |
| 栈操作 |
peek() |
相当于 peekFirst |
作为栈(LIFO)
1 2 3 4 5 6 7 8
| Deque<String> stack = new ArrayDeque<>();
stack.push("A"); stack.push("B"); stack.push("C");
System.out.println(stack.pop()); System.out.println(stack.peek());
|
作为队列(FIFO)
1 2 3 4 5 6 7 8
| Deque<String> queue = new ArrayDeque<>();
queue.offer("A"); queue.offer("B"); queue.offer("C");
System.out.println(queue.poll()); System.out.println(queue.peek());
|
PriorityQueue
创建
1 2 3 4
| PriorityQueue<>(); PriorityQueue<>(int initialCapacity); PriorityQueue<>(Comparator comparator); PriorityQueue<>(Collection c);
|
| 方法 |
描述 |
boolean add(E e) |
添加元素,若超出容量自动扩容,抛出异常(推荐用 offer()) |
boolean offer(E e) |
添加元素,返回 true 或 false |
E poll() |
取出并移除队首元素(最小或最大),为空返回 null |
E peek() |
获取队首元素但不移除,队列为空返回 null |
E remove() |
移除并返回队首元素,若为空则抛出异常 |
boolean remove(Object o) |
删除队列中指定元素,成功返回 true |
boolean contains(Object o) |
判断队列是否包含某个元素 |
int size() |
获取队列中元素数量 |
void clear() |
清空队列 |
boolean isEmpty() |
判断队列是否为空 |
Object[] toArray() |
转为数组(无排序保证) |
<T> T[] toArray(T[] a) |
转为指定类型的数组 |
ArrayBlockingQueue \ LinkedBlockingQueue
Map
HashMap / LinkedHashMap
| 基本方法 |
描述 |
V put(K key, V value) |
添加键值对,若 key 已存在,则更新并返回旧值 |
V get(Object key) |
获取指定 key 对应的 value,若不存在则返回 null |
V remove(Object key) |
移除指定 key 的键值对,并返回被删除的 value |
boolean containsKey(Object key) |
是否包含指定的 key |
boolean containsValue(Object value) |
是否包含指定的 value |
int size() |
返回映射中键值对的数量 |
boolean isEmpty() |
是否为空 |
void clear() |
清空所有键值对 |
| 遍历方法 |
描述 |
Set<K> keySet() |
返回所有键组成的 Set 视图 |
Collection<V> values() |
返回所有值组成的 Collection 视图 |
Set<Map.Entry<K, V>> entrySet() |
返回所有键值对的集合(每个元素是一个 Map.Entry) |
| 方法 |
描述 |
V getOrDefault(Object key, V defaultValue) |
获取指定 key 的 value,如果不存在返回默认值 |
V putIfAbsent(K key, V value) |
如果 key 不存在才放入 |
boolean replace(K key, V oldValue, V newValue) |
替换指定 key 的 value,要求当前值等于 oldValue |
V replace(K key, V value) |
替换 key 对应的 value,不判断旧值 |
void forEach(BiConsumer<K,V> action) |
对每个键值对执行操作(lambda) |
void compute(K key, BiFunction...) |
根据 key 和旧值计算新值放入 |
void merge(K key, V value, BiFunction...) |
如果 key 存在合并,不存在则添加 |
void computeIfAbsent(K key, Function...) |
key 不存在时,计算一个值并放入 |
void computeIfPresent(K key, BiFunction...) |
key 存在时,根据旧值计算新值放入 |