说明
由于之前主要使用golang,工作中需要使用到java,之前都是比较零碎的学习java的一些八股文,现在打算系统性的学习java并做一些记录,这一篇Java Colleciton Framework相关的就当做一个开始
Java Collection Framework 介绍
Java Collection Framework 是Java标准库中的一个重要部分,它提供了一套统一的架构来存储和操作对象组。这个框架包含了许多接口、实现类和算法,使得开发者能够更加高效地处理数据集合。
主要组成部分
接口(Interfaces):定义了集合的抽象数据类型。主要接口包括:
- Iterable
- Collection
- List
- Set
- Queue
- Map(技术上不是Collection的子接口,但通常被视为集合框架的一部分)
整体类关系图,Colleciton
和Map
是两个顶层接口,两者都继承了Iterator
接口
Collection相关的接口
Collection 接口
- 继承自 Iterable 接口
- 是 List、Set 和 Queue 的父接口
- 定义了集合的基本操作,如 add(), remove(), contains() 等
List的具体例子
ArrayList
和 LinkedList
// 初始化
List<Integer> al = new ArrayList<>(10);
System.out.println(al.size());
// add
al.add(100);
// 使用实现collection接口的集合初始化
List<Integer> ll = new LinkedList<>(al);
System.out.println(ll.size());
// forEach, iterator
ll.forEach(System.out::println);
ll.add(101);
// get by index, ArrayList和LinkedList都是支持的
al.get(0);
ll.get(1);
// set
al.set(0, 100);
ll.set(1, 1000);
// clear
al.clear();
ll.clear();
// remove by index
int targetIdx = 0;
Integer tv = ll.remove(targetIdx); // 如果targetIdx 超出了list的范围会有java.lang.IndexOutOfBoundsException 异常抛出
// remove by element
Integer target = 101;
boolean success = ll.remove(target); // 如果target不存在,也不会抛异常,用success来做判断就行了
// contains
boolean exists = ll.contains(100);
// indexOf和lastIndexOf
ll.indexOf(100);
ll.lastIndexOf(1000);
// addAll, removeAll, containsAll
List<Interger> opCol = List.of(1, 2, 3, 4);
ll.addAll(opCol);
ll.removeAll(opCol);
ll.containsAll(opCol);
// sort
al.sort(Integer::compareTo);
ll.sort(Integer::compareTo);
// iterator
al.clear();
al.addAll(List.of(1, 2, 3, 4));
Iterator<Integer> ai = al.iterator();
while (ai.hasNext()) {
System.out.println(ai.next());
}
// listIterator, 可以前向遍历
ListIterator<Integer> ali = al.listIterator(al.size());
while(ali.hasPrevious()) {
System.out.printf("%d ", ali.previous());
}
System.out.println();
// subList 浅拷贝
List<Integer> sub = ll.subList(1, ll.size());
sub.set(0, 1000);
System.out.println(Arrays.toString(sub.toArray())); // [1000, 3, 4]
System.out.println(Arrays.toString(ll.toArray())); // [1, 1000, 3, 4]
// SplitIterator
List<String> fruits = Arrays.asList("Apple", "Banana", "Cherry", "Date", "Elephant");
Spliterator<String> spliterator = fruits.spliterator();
// trySplit之后返回的spliterator是原来数据的前面部分,老的spliterator继承了下半部分
Spliterator<String> splitSpliterator = spliterator.trySplit();
splitSpliterator.forEachRemaining(System.out::println); // Apple, Banana
spliterator.forEachRemaining(System.out::println); // Cherry, Date, Elephant
Queue相关的例子
// LinkedList Queue
Queue<Integer> lq = new LinkedList<>(List.of(1, 2, 3, 4));
System.out.println(lq.size());
boolean success = lq.add(5);
System.out.println("add result: " + success);
success = lq.offer(6);
System.out.println("offer result: " + success);
Integer top = lq.peek();
System.out.println("top: " + top);
System.out.println("before poll queue size: " + lq.size());
top = lq.poll();
System.out.println("after poll queue size: " + lq.size() + ", top: " + top);
// PriorityQueue
PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.offer(3);
pq.offer(2);
pq.offer(1);
Integer pqTop = pq.poll();
System.out.println("top: " + pqTop + ", pq size: " + pq.size());
// LinkedBlockingQueue
LinkedBlockingQueue<Integer> linkedBlockingQueue = new LinkedBlockingQueue<>(2);
// 非阻塞方法
linkedBlockingQueue.offer(1);
linkedBlockingQueue.offer(2);
success = linkedBlockingQueue.offer(3);
System.out.println("over capacity add success: " + success);
try {
success = linkedBlockingQueue.offer(3, 1, TimeUnit.SECONDS);
System.out.println("timeout offer returns: " + success);
} catch (InterruptedException e) {
System.out.println("offer timeout");
e.printStackTrace();
}
// 非阻塞方法
linkedBlockingQueue.poll();
try {
linkedBlockingQueue.take();
pqTop = linkedBlockingQueue.poll(1, TimeUnit.SECONDS);
System.out.println("poll with timeout returns: " + pqTop);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 阻塞方法put和take示例
LinkedBlockingQueue<Integer> linkedBlockingQueue = new LinkedBlockingQueue<>(1);
Thread thread1 = new Thread(() -> {
try {
Thread.sleep(1000);
Integer top = linkedBlockingQueue.take();
System.out.println("top: " + top);
} catch (InterruptedException e) {
// pass
}
});
Thread thread2 = new Thread(() -> {
try {
long start = System.currentTimeMillis();
linkedBlockingQueue.put(1);
System.out.println("first put consumes: " + (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
linkedBlockingQueue.put(2);
System.out.println("second put consumes: " + (System.currentTimeMillis() - start));
} catch (InterruptedException e) {
// pass
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
// Deque
Deque<Integer> dq = new LinkedList<>();
dq.offerLast(1);
dq.offer(2);
dq.offerFirst(3);
Integer top = dq.peek();
System.out.println("top(peek, peekFirst):" + top);
top = dq.peekLast();
System.out.println("peekLast: " + top);
while (!dq.isEmpty()) {
System.out.println(dq.pollLast());
}
Set相关的例子
Set<Integer> s1 = new HashSet<>(List.of(1, 1, 2, 2, 3, 3));
System.out.println(s1.size());
Iterator iterator = s1.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
System.out.println(s1.contains(4));
System.out.println(s1.contains(2));
TreeSet<Integer> treeSet = new TreeSet<>(List.of(1, 2, 3, 4, 5, 6));
for (Integer v: treeSet) {
System.out.println("treeSet member: " + v);
}
System.out.println("treeSet first: " + treeSet.first());
System.out.println("treeSet last: " + treeSet.last());
SortedSet<Integer> tailSet = treeSet.tailSet(4);
for (Integer v: tailSet) {
System.out.println("tailSet: " + v);
}
SortedSet<Integer> headSet = treeSet.headSet(4);
for (Integer v: headSet) {
System.out.println("headSet: " + v);
}
TreeSet<Integer> treeSet1 = new TreeSet<>(Comparator.reverseOrder());
treeSet1.addAll(List.of(1, 2, 3, 4, 5, 6));
for(Integer v: treeSet1) {
System.out.println("reverse set: " + v);
}
Map相关的接口
HashMap的例子
Map<Integer, Integer> map = new HashMap<>();
map.put(1, 11);
map.put(2, 22);
System.out.println(map.containsKey(1));
// O(n)
System.out.println(map.containsValue(11));
for(Map.Entry<Integer, Integer> entry: map.entrySet()) {
System.out.println("key: " + entry.getKey() + ", value: " + entry.getValue());
}
Integer oldValue = map.remove(1);
System.out.println("oldValue: " + oldValue);
TreeMap相关的例子
TreeMap<Integer, Integer> treeMap = new TreeMap<>();
treeMap.put(3, 33);
treeMap.put(2, 22);
treeMap.put(1, 11);
for(Map.Entry<Integer, Integer> entry: treeMap.entrySet()) {
System.out.println("key: " + entry.getKey() + ", value: " + entry.getValue());
}
Integer lowerKey = treeMap.lowerKey(2);
System.out.println("lowerKey: " + lowerKey);
Integer higherKey = treeMap.higherKey(2);
System.out.println("higherKey: " + higherKey);
Integer floorKey = treeMap.floorKey(2);
Integer ceilingKey = treeMap.ceilingKey(2);
System.out.printf("floorKey = %d, ceilingKey = %d\n", floorKey, ceilingKey);
能保证插入顺序的集合
// LinkedHashSet, LinkedHashMap, LinkedHashSet底层和LinkedHashMap一致
LinkedHashMap<Integer, Integer> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put(1, 2);
linkedHashMap.put(2, 3);
linkedHashMap.put(3, 4);
for (var e : linkedHashMap.entrySet()) {
System.out.println("key = " + e.getKey() + ", value = " + e.getValue());
}
底层数据结构
-
ArrayList: 数组
-
LinkedList: 链表
-
PriorityQueue: 堆
-
HashSet和HashMap: 都是基于HashMap
-
TreeMap: 红黑树
-
LinkedHashSet和LinkedHashMap:基于HashMap,然后使用链表保存了插入顺序
算法(Algorithms):这些是在集合上执行的方法,如搜索和排序。它们通常以静态方法的形式存在于Collections类中。
// sort
List<Integer> numbers = Arrays.asList(2, 1, 3, 4, 5);
Collections.sort(numbers);
System.out.println(Arrays.toString(numbers.toArray()));
Collections.sort(numbers, Collections.reverseOrder());
System.out.println(Arrays.toString(numbers.toArray()));
// binarySearch
int idx = Collections.binarySearch(numbers, 1);
System.out.println("1 idx: " + idx);
idx = Collections.binarySearch(numbers, 10);
System.out.println("10 idx: " + idx);
// shuffle
Collections.shuffle(numbers);
System.out.println(Arrays.toString(numbers.toArray()));
// reverse
Collections.reverse(numbers);
System.out.println(Arrays.toString(numbers.toArray()));