Java 集合框架
本章内容
本章介绍 Java 集合框架:Collection 接口体系、Map 接口体系、集合选择指南和遍历方法。
一、集合框架概述
1.1 集合框架结构
/*
Java 集合框架层次结构:
Iterable
└── Collection
├── List (有序,可重复)
│ ├── ArrayList
│ ├── LinkedList
│ └── Vector
├── Set (无序,不可重复)
│ ├── HashSet
│ ├── LinkedHashSet
│ └── TreeSet
└── Queue (队列)
├── LinkedList
├── PriorityQueue
└── ArrayDeque
Map (键值对,键不可重复)
├── HashMap
├── LinkedHashMap
├── TreeMap
└── Hashtable
*/
import java.util.*;
public class CollectionFrameworkOverview {
public static void main(String[] args) {
System.out.println("=== Java 集合框架概述 ===");
// Collection 接口的主要方法
demonstrateCollectionMethods();
// 集合的基本特性
demonstrateCollectionCharacteristics();
}
public static void demonstrateCollectionMethods() {
System.out.println("\n--- Collection 接口主要方法 ---");
Collection<String> collection = new ArrayList<>();
// 添加元素
collection.add("Apple");
collection.add("Banana");
collection.add("Cherry");
System.out.println("添加元素后: " + collection);
// 查询操作
System.out.println("集合大小: " + collection.size());
System.out.println("是否为空: " + collection.isEmpty());
System.out.println("是否包含Apple: " + collection.contains("Apple"));
// 批量操作
Collection<String> fruits = Arrays.asList("Orange", "Grape");
collection.addAll(fruits);
System.out.println("批量添加后: " + collection);
// 删除操作
collection.remove("Banana");
System.out.println("删除Banana后: " + collection);
// 转换为数组
String[] array = collection.toArray(new String[0]);
System.out.println("转换为数组: " + Arrays.toString(array));
}
public static void demonstrateCollectionCharacteristics() {
System.out.println("\n--- 集合特性对比 ---");
// List: 有序,可重复
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("A"); // 可重复
System.out.println("List (有序,可重复): " + list);
// Set: 无序,不可重复
Set<String> set = new HashSet<>();
set.add("A");
set.add("B");
set.add("A"); // 重复元素不会被添加
System.out.println("Set (无序,不可重复): " + set);
// Map: 键值对,键不可重复
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 10);
map.put("Banana", 20);
map.put("Apple", 15); // 键重复,值会被覆盖
System.out.println("Map (键值对,键不可重复): " + map);
}
}
二、List 接口及其实现
2.1 ArrayList
import java.util.*;
public class ArrayListDemo {
public static void main(String[] args) {
System.out.println("=== ArrayList 详解 ===");
// 创建和初始化
createAndInitialize();
// 基本操作
basicOperations();
// 性能特点
performanceCharacteristics();
// 线程安全问题
threadSafetyIssue();
}
public static void createAndInitialize() {
System.out.println("\n--- 创建和初始化 ---");
// 1. 默认构造器
ArrayList<String> list1 = new ArrayList<>();
System.out.println("默认容量的ArrayList: " + list1.size());
// 2. 指定初始容量
ArrayList<String> list2 = new ArrayList<>(20);
System.out.println("指定容量的ArrayList: " + list2.size());
// 3. 从其他集合创建
List<String> sourceList = Arrays.asList("A", "B", "C");
ArrayList<String> list3 = new ArrayList<>(sourceList);
System.out.println("从其他集合创建: " + list3);
// 4. 使用集合工厂方法(Java 9+)
List<String> list4 = List.of("X", "Y", "Z"); // 不可变列表
System.out.println("不可变列表: " + list4);
}
public static void basicOperations() {
System.out.println("\n--- 基本操作 ---");
ArrayList<String> list = new ArrayList<>();
// 添加元素
list.add("First");
list.add("Second");
list.add(1, "Middle"); // 在指定位置插入
System.out.println("添加元素后: " + list);
// 访问元素
System.out.println("第一个元素: " + list.get(0));
System.out.println("最后一个元素: " + list.get(list.size() - 1));
// 修改元素
String oldValue = list.set(1, "Updated");
System.out.println("修改元素,旧值: " + oldValue + ", 新列表: " + list);
// 查找元素
int index = list.indexOf("Second");
System.out.println("Second的索引: " + index);
// 删除元素
list.remove("First"); // 按值删除
list.remove(0); // 按索引删除
System.out.println("删除元素后: " + list);
// 子列表
list.addAll(Arrays.asList("A", "B", "C", "D"));
List<String> subList = list.subList(1, 3);
System.out.println("子列表: " + subList);
}
public static void performanceCharacteristics() {
System.out.println("\n--- 性能特点 ---");
ArrayList<Integer> list = new ArrayList<>();
// 测试添加性能
long startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
list.add(i);
}
long endTime = System.nanoTime();
System.out.println("添加10万个元素耗时: " + (endTime - startTime) / 1000000 + "ms");
// 测试随机访问性能
startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
int randomIndex = (int) (Math.random() * list.size());
list.get(randomIndex);
}
endTime = System.nanoTime();
System.out.println("随机访问1万次耗时: " + (endTime - startTime) / 1000000 + "ms");
// 测试中间插入性能
startTime = System.nanoTime();
for (int i = 0; i < 1000; i++) {
list.add(list.size() / 2, i);
}
endTime = System.nanoTime();
System.out.println("中间插入1000次耗时: " + (endTime - startTime) / 1000000 + "ms");
}
public static void threadSafetyIssue() {
System.out.println("\n--- 线程安全问题 ---");
// ArrayList 不是线程安全的
ArrayList<Integer> unsafeList = new ArrayList<>();
// 线程安全的替代方案
// 1. 使用 Collections.synchronizedList
List<Integer> syncList = Collections.synchronizedList(new ArrayList<>());
// 2. 使用 Vector(不推荐,性能较差)
Vector<Integer> vector = new Vector<>();
// 3. 使用 CopyOnWriteArrayList(读多写少场景)
// CopyOnWriteArrayList<Integer> cowList = new CopyOnWriteArrayList<>();
System.out.println("线程安全的List创建完成");
}
}
2.2 LinkedList
import java.util.*;
public class LinkedListDemo {
public static void main(String[] args) {
System.out.println("=== LinkedList 详解 ===");
// 基本操作
basicOperations();
// 队列操作
queueOperations();
// 栈操作
stackOperations();
// 性能对比
performanceComparison();
}
public static void basicOperations() {
System.out.println("\n--- 基本操作 ---");
LinkedList<String> list = new LinkedList<>();
// 添加元素
list.add("Middle");
list.addFirst("First");
list.addLast("Last");
System.out.println("添加元素后: " + list);
// 访问元素
System.out.println("第一个元素: " + list.getFirst());
System.out.println("最后一个元素: " + list.getLast());
System.out.println("索引1的元素: " + list.get(1));
// 删除元素
String removedFirst = list.removeFirst();
String removedLast = list.removeLast();
System.out.println("删除的第一个: " + removedFirst + ", 删除的最后一个: " + removedLast);
System.out.println("删除后: " + list);
}
public static void queueOperations() {
System.out.println("\n--- 队列操作 ---");
Queue<String> queue = new LinkedList<>();
// 入队
queue.offer("First");
queue.offer("Second");
queue.offer("Third");
System.out.println("入队后: " + queue);
// 查看队首元素
System.out.println("队首元素: " + queue.peek());
// 出队
while (!queue.isEmpty()) {
String element = queue.poll();
System.out.println("出队: " + element + ", 剩余: " + queue);
}
}
public static void stackOperations() {
System.out.println("\n--- 栈操作 ---");
LinkedList<String> stack = new LinkedList<>();
// 压栈
stack.push("Bottom");
stack.push("Middle");
stack.push("Top");
System.out.println("压栈后: " + stack);
// 查看栈顶元素
System.out.println("栈顶元素: " + stack.peek());
// 弹栈
while (!stack.isEmpty()) {
String element = stack.pop();
System.out.println("弹栈: " + element + ", 剩余: " + stack);
}
}
public static void performanceComparison() {
System.out.println("\n--- ArrayList vs LinkedList 性能对比 ---");
int size = 100000;
// ArrayList
ArrayList<Integer> arrayList = new ArrayList<>();
long startTime = System.nanoTime();
for (int i = 0; i < size; i++) {
arrayList.add(0, i); // 在开头插入
}
long arrayListTime = System.nanoTime() - startTime;
// LinkedList
LinkedList<Integer> linkedList = new LinkedList<>();
startTime = System.nanoTime();
for (int i = 0; i < size; i++) {
linkedList.addFirst(i); // 在开头插入
}
long linkedListTime = System.nanoTime() - startTime;
System.out.println("在开头插入" + size + "个元素:");
System.out.println("ArrayList: " + arrayListTime / 1000000 + "ms");
System.out.println("LinkedList: " + linkedListTime / 1000000 + "ms");
// 随机访问性能对比
startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
arrayList.get(i);
}
long arrayListAccessTime = System.nanoTime() - startTime;
startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
linkedList.get(i);
}
long linkedListAccessTime = System.nanoTime() - startTime;
System.out.println("\n随机访问性能对比:");
System.out.println("ArrayList: " + arrayListAccessTime / 1000000 + "ms");
System.out.println("LinkedList: " + linkedListAccessTime / 1000000 + "ms");
}
}
三、Set 接口及其实现
3.1 HashSet
import java.util.*;
public class HashSetDemo {
public static void main(String[] args) {
System.out.println("=== HashSet 详解 ===");
// 基本操作
basicOperations();
// 去重特性
duplicateRemoval();
// 自定义对象的HashSet
customObjectHashSet();
// 性能特点
performanceCharacteristics();
}
public static void basicOperations() {
System.out.println("\n--- 基本操作 ---");
HashSet<String> set = new HashSet<>();
// 添加元素
set.add("Apple");
set.add("Banana");
set.add("Cherry");
set.add("Apple"); // 重复元素不会被添加
System.out.println("添加元素后: " + set);
// 查询操作
System.out.println("集合大小: " + set.size());
System.out.println("是否包含Apple: " + set.contains("Apple"));
System.out.println("是否为空: " + set.isEmpty());
// 删除操作
boolean removed = set.remove("Banana");
System.out.println("删除Banana: " + removed + ", 结果: " + set);
// 集合运算
HashSet<String> otherSet = new HashSet<>(Arrays.asList("Apple", "Date", "Elderberry"));
// 交集
HashSet<String> intersection = new HashSet<>(set);
intersection.retainAll(otherSet);
System.out.println("交集: " + intersection);
// 并集
HashSet<String> union = new HashSet<>(set);
union.addAll(otherSet);
System.out.println("并集: " + union);
// 差集
HashSet<String> difference = new HashSet<>(set);
difference.removeAll(otherSet);
System.out.println("差集: " + difference);
}
public static void duplicateRemoval() {
System.out.println("\n--- 去重特性 ---");
// 数组去重
Integer[] array = {1, 2, 3, 2, 4, 3, 5, 1};
HashSet<Integer> uniqueSet = new HashSet<>(Arrays.asList(array));
System.out.println("原数组: " + Arrays.toString(array));
System.out.println("去重后: " + uniqueSet);
// 转回数组
Integer[] uniqueArray = uniqueSet.toArray(new Integer[0]);
System.out.println("去重数组: " + Arrays.toString(uniqueArray));
}
public static void customObjectHashSet() {
System.out.println("\n--- 自定义对象的HashSet ---");
HashSet<Person> personSet = new HashSet<>();
Person p1 = new Person("张三", 25);
Person p2 = new Person("李四", 30);
Person p3 = new Person("张三", 25); // 与p1相同
personSet.add(p1);
personSet.add(p2);
personSet.add(p3);
System.out.println("Person集合大小: " + personSet.size());
for (Person p : personSet) {
System.out.println(p);
}
}
public static void performanceCharacteristics() {
System.out.println("\n--- 性能特点 ---");
HashSet<Integer> set = new HashSet<>();
// 添加性能
long startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
set.add(i);
}
long addTime = System.nanoTime() - startTime;
// 查找性能
startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
set.contains(i);
}
long containsTime = System.nanoTime() - startTime;
System.out.println("添加10万个元素耗时: " + addTime / 1000000 + "ms");
System.out.println("查找10万次耗时: " + containsTime / 1000000 + "ms");
}
}
// 自定义Person类,重写equals和hashCode
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
// getter方法
public String getName() { return name; }
public int getAge() { return age; }
}
3.2 TreeSet
import java.util.*;
public class TreeSetDemo {
public static void main(String[] args) {
System.out.println("=== TreeSet 详解 ===");
// 基本操作
basicOperations();
// 排序特性
sortingFeatures();
// 自定义排序
customSorting();
// 范围操作
rangeOperations();
}
public static void basicOperations() {
System.out.println("\n--- 基本操作 ---");
TreeSet<Integer> treeSet = new TreeSet<>();
// 添加元素(自动排序)
treeSet.add(5);
treeSet.add(2);
treeSet.add(8);
treeSet.add(1);
treeSet.add(9);
System.out.println("添加元素后(自动排序): " + treeSet);
// 访问第一个和最后一个元素
System.out.println("最小元素: " + treeSet.first());
System.out.println("最大元素: " + treeSet.last());
// 删除第一个和最后一个元素
System.out.println("删除并返回最小元素: " + treeSet.pollFirst());
System.out.println("删除并返回最大元素: " + treeSet.pollLast());
System.out.println("删除后: " + treeSet);
}
public static void sortingFeatures() {
System.out.println("\n--- 排序特性 ---");
// 字符串的自然排序
TreeSet<String> stringSet = new TreeSet<>();
stringSet.addAll(Arrays.asList("banana", "apple", "cherry", "date"));
System.out.println("字符串排序: " + stringSet);
// 数字的自然排序
TreeSet<Double> numberSet = new TreeSet<>();
numberSet.addAll(Arrays.asList(3.14, 2.71, 1.41, 1.73));
System.out.println("数字排序: " + numberSet);
}
public static void customSorting() {
System.out.println("\n--- 自定义排序 ---");
// 使用Comparator进行自定义排序
// 1. 按字符串长度排序
TreeSet<String> lengthSortedSet = new TreeSet<>(Comparator.comparing(String::length));
lengthSortedSet.addAll(Arrays.asList("a", "hello", "world", "java", "programming"));
System.out.println("按长度排序: " + lengthSortedSet);
// 2. 逆序排序
TreeSet<Integer> reverseSet = new TreeSet<>(Collections.reverseOrder());
reverseSet.addAll(Arrays.asList(1, 5, 3, 9, 2, 7));
System.out.println("逆序排序: " + reverseSet);
// 3. 自定义对象排序
TreeSet<Student> studentSet = new TreeSet<>(Comparator.comparing(Student::getScore).reversed());
studentSet.add(new Student("张三", 85));
studentSet.add(new Student("李四", 92));
studentSet.add(new Student("王五", 78));
studentSet.add(new Student("赵六", 95));
System.out.println("学生按分数降序排序:");
for (Student student : studentSet) {
System.out.println(student);
}
}
public static void rangeOperations() {
System.out.println("\n--- 范围操作 ---");
TreeSet<Integer> set = new TreeSet<>();
for (int i = 1; i <= 10; i++) {
set.add(i);
}
System.out.println("原集合: " + set);
// 子集操作
System.out.println("小于5的元素: " + set.headSet(5));
System.out.println("大于等于7的元素: " + set.tailSet(7));
System.out.println("3到8之间的元素: " + set.subSet(3, 8));
// 查找操作
System.out.println("小于等于6的最大元素: " + set.floor(6));
System.out.println("大于等于6的最小元素: " + set.ceiling(6));
System.out.println("小于6的最大元素: " + set.lower(6));
System.out.println("大于6的最小元素: " + set.higher(6));
}
}
class Student {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() { return name; }
public int getScore() { return score; }
@Override
public String toString() {
return "Student{name='" + name + "', score=" + score + "}";
}
}
四、Map 接口及其实现
4.1 HashMap
import java.util.*;
public class HashMapDemo {
public static void main(String[] args) {
System.out.println("=== HashMap 详解 ===");
// 基本操作
basicOperations();
// 遍历方式
iterationMethods();
// 常用方法
commonMethods();
// 性能特点
performanceCharacteristics();
}
public static void basicOperations() {
System.out.println("\n--- 基本操作 ---");
HashMap<String, Integer> map = new HashMap<>();
// 添加键值对
map.put("Apple", 10);
map.put("Banana", 20);
map.put("Cherry", 15);
System.out.println("添加元素后: " + map);
// 获取值
Integer appleCount = map.get("Apple");
System.out.println("Apple的数量: " + appleCount);
// 获取值(带默认值)
Integer orangeCount = map.getOrDefault("Orange", 0);
System.out.println("Orange的数量(默认值): " + orangeCount);
// 检查键和值
System.out.println("是否包含键Apple: " + map.containsKey("Apple"));
System.out.println("是否包含值20: " + map.containsValue(20));
// 删除元素
Integer removedValue = map.remove("Banana");
System.out.println("删除Banana,返回值: " + removedValue);
System.out.println("删除后: " + map);
// 替换值
map.replace("Apple", 25);
System.out.println("替换Apple的值后: " + map);
}
public static void iterationMethods() {
System.out.println("\n--- 遍历方式 ---");
Map<String, Integer> map = new HashMap<>();
map.put("Java", 25);
map.put("Python", 30);
map.put("JavaScript", 28);
map.put("C++", 35);
// 1. 遍历键
System.out.println("遍历键:");
for (String key : map.keySet()) {
System.out.println("Key: " + key + ", Value: " + map.get(key));
}
// 2. 遍历值
System.out.println("\n遍历值:");
for (Integer value : map.values()) {
System.out.println("Value: " + value);
}
// 3. 遍历键值对
System.out.println("\n遍历键值对:");
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
// 4. 使用Lambda表达式(Java 8+)
System.out.println("\n使用Lambda表达式:");
map.forEach((key, value) -> System.out.println(key + " -> " + value));
// 5. 使用Stream API
System.out.println("\n使用Stream API过滤:");
map.entrySet().stream()
.filter(entry -> entry.getValue() > 28)
.forEach(entry -> System.out.println(entry.getKey() + ": " + entry.getValue()));
}
public static void commonMethods() {
System.out.println("\n--- 常用方法 ---");
HashMap<String, List<String>> groupMap = new HashMap<>();
// putIfAbsent - 如果键不存在才添加
groupMap.putIfAbsent("fruits", new ArrayList<>());
groupMap.get("fruits").add("apple");
groupMap.get("fruits").add("banana");
groupMap.putIfAbsent("vegetables", new ArrayList<>());
groupMap.get("vegetables").add("carrot");
System.out.println("分组数据: " + groupMap);
// compute - 计算新值
HashMap<String, Integer> countMap = new HashMap<>();
String[] words = {"apple", "banana", "apple", "cherry", "banana", "apple"};
for (String word : words) {
countMap.compute(word, (key, value) -> (value == null) ? 1 : value + 1);
}
System.out.println("单词计数: " + countMap);
// merge - 合并值
HashMap<String, Integer> map1 = new HashMap<>();
map1.put("a", 1);
map1.put("b", 2);
HashMap<String, Integer> map2 = new HashMap<>();
map2.put("b", 3);
map2.put("c", 4);
// 将map2合并到map1中
map2.forEach((key, value) -> map1.merge(key, value, Integer::sum));
System.out.println("合并后的map: " + map1);
}
public static void performanceCharacteristics() {
System.out.println("\n--- 性能特点 ---");
HashMap<Integer, String> map = new HashMap<>();
// 测试插入性能
long startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
map.put(i, "Value" + i);
}
long insertTime = System.nanoTime() - startTime;
// 测试查找性能
startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
map.get(i);
}
long searchTime = System.nanoTime() - startTime;
System.out.println("插入10万个元素耗时: " + insertTime / 1000000 + "ms");
System.out.println("查找10万次耗时: " + searchTime / 1000000 + "ms");
// 负载因子的影响
System.out.println("\n负载因子对性能的影响:");
testLoadFactor(0.5f);
testLoadFactor(0.75f); // 默认值
testLoadFactor(1.0f);
}
private static void testLoadFactor(float loadFactor) {
HashMap<Integer, String> map = new HashMap<>(16, loadFactor);
long startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
map.put(i, "Value" + i);
}
long time = System.nanoTime() - startTime;
System.out.println("负载因子 " + loadFactor + " 插入耗时: " + time / 1000000 + "ms");
}
}
4.2 TreeMap
import java.util.*;
public class TreeMapDemo {
public static void main(String[] args) {
System.out.println("=== TreeMap 详解 ===");
// 基本操作
basicOperations();
// 排序特性
sortingFeatures();
// 范围操作
rangeOperations();
// 导航方法
navigationMethods();
}
public static void basicOperations() {
System.out.println("\n--- 基本操作 ---");
TreeMap<String, Integer> treeMap = new TreeMap<>();
// 添加元素(按键自动排序)
treeMap.put("Charlie", 25);
treeMap.put("Alice", 30);
treeMap.put("Bob", 28);
treeMap.put("David", 35);
System.out.println("添加元素后(按键排序): " + treeMap);
// 获取第一个和最后一个键值对
System.out.println("第一个键值对: " + treeMap.firstEntry());
System.out.println("最后一个键值对: " + treeMap.lastEntry());
// 获取第一个和最后一个键
System.out.println("第一个键: " + treeMap.firstKey());
System.out.println("最后一个键: " + treeMap.lastKey());
}
public static void sortingFeatures() {
System.out.println("\n--- 排序特性 ---");
// 自然排序(字符串)
TreeMap<String, String> naturalOrder = new TreeMap<>();
naturalOrder.put("zebra", "斑马");
naturalOrder.put("apple", "苹果");
naturalOrder.put("banana", "香蕉");
System.out.println("自然排序: " + naturalOrder);
// 自定义排序(按键长度)
TreeMap<String, String> lengthOrder = new TreeMap<>(Comparator.comparing(String::length));
lengthOrder.put("a", "短");
lengthOrder.put("hello", "中等");
lengthOrder.put("programming", "长");
System.out.println("按长度排序: " + lengthOrder);
// 逆序排序
TreeMap<Integer, String> reverseOrder = new TreeMap<>(Collections.reverseOrder());
reverseOrder.put(1, "一");
reverseOrder.put(3, "三");
reverseOrder.put(2, "二");
reverseOrder.put(5, "五");
System.out.println("逆序排序: " + reverseOrder);
}
public static void rangeOperations() {
System.out.println("\n--- 范围操作 ---");
TreeMap<Integer, String> map = new TreeMap<>();
for (int i = 1; i <= 10; i++) {
map.put(i, "Value" + i);
}
System.out.println("原Map: " + map);
// 子Map操作
System.out.println("键小于5的子Map: " + map.headMap(5));
System.out.println("键大于等于7的子Map: " + map.tailMap(7));
System.out.println("键在3到8之间的子Map: " + map.subMap(3, 8));
// 包含边界的子Map
System.out.println("键在3到8之间(包含8): " + map.subMap(3, true, 8, true));
}
public static void navigationMethods() {
System.out.println("\n--- 导航方法 ---");
TreeMap<Integer, String> map = new TreeMap<>();
int[] keys = {1, 3, 5, 7, 9, 11, 13, 15};
for (int key : keys) {
map.put(key, "Value" + key);
}
System.out.println("原Map: " + map);
int searchKey = 8;
System.out.println("\n查找键: " + searchKey);
// 查找操作
System.out.println("小于等于" + searchKey + "的最大键: " + map.floorKey(searchKey));
System.out.println("大于等于" + searchKey + "的最小键: " + map.ceilingKey(searchKey));
System.out.println("小于" + searchKey + "的最大键: " + map.lowerKey(searchKey));
System.out.println("大于" + searchKey + "的最小键: " + map.higherKey(searchKey));
// 对应的Entry操作
System.out.println("\n对应的Entry操作:");
System.out.println("floorEntry: " + map.floorEntry(searchKey));
System.out.println("ceilingEntry: " + map.ceilingEntry(searchKey));
System.out.println("lowerEntry: " + map.lowerEntry(searchKey));
System.out.println("higherEntry: " + map.higherEntry(searchKey));
// 删除并返回第一个和最后一个
System.out.println("\n删除操作:");
System.out.println("删除并返回第一个: " + map.pollFirstEntry());
System.out.println("删除并返回最后一个: " + map.pollLastEntry());
System.out.println("删除后: " + map);
}
}
五、集合选择指南
5.1 集合选择决策树
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
public class CollectionSelectionGuide {
public static void main(String[] args) {
System.out.println("=== 集合选择指南 ===");
// 演示不同场景下的集合选择
demonstrateListSelection();
demonstrateSetSelection();
demonstrateMapSelection();
demonstrateQueueSelection();
// 性能对比
performanceComparison();
}
public static void demonstrateListSelection() {
System.out.println("\n--- List 选择指南 ---");
// 场景1:频繁随机访问
System.out.println("场景1:频繁随机访问 -> 选择ArrayList");
List<Integer> arrayList = new ArrayList<>();
// ArrayList 提供 O(1) 的随机访问
// 场景2:频繁在开头/中间插入删除
System.out.println("场景2:频繁在开头/中间插入删除 -> 选择LinkedList");
List<Integer> linkedList = new LinkedList<>();
// LinkedList 提供 O(1) 的插入删除(如果有引用)
// 场景3:线程安全需求
System.out.println("场景3:线程安全 -> 选择Vector或Collections.synchronizedList");
List<Integer> syncList = Collections.synchronizedList(new ArrayList<>());
Vector<Integer> vector = new Vector<>();
// 场景4:读多写少的并发场景
System.out.println("场景4:读多写少并发 -> 选择CopyOnWriteArrayList");
List<Integer> cowList = new CopyOnWriteArrayList<>();
}
public static void demonstrateSetSelection() {
System.out.println("\n--- Set 选择指南 ---");
// 场景1:快速查找,不需要排序
System.out.println("场景1:快速查找,无序 -> 选择HashSet");
Set<String> hashSet = new HashSet<>();
// HashSet 提供 O(1) 的查找性能
// 场景2:需要保持插入顺序
System.out.println("场景2:保持插入顺序 -> 选择LinkedHashSet");
Set<String> linkedHashSet = new LinkedHashSet<>();
// 场景3:需要排序
System.out.println("场景3:需要排序 -> 选择TreeSet");
Set<String> treeSet = new TreeSet<>();
// TreeSet 提供 O(log n) 的操作,但元素有序
// 场景4:枚举类型
System.out.println("场景4:枚举类型 -> 选择EnumSet");
Set<DayOfWeek> enumSet = EnumSet.allOf(DayOfWeek.class);
}
public static void demonstrateMapSelection() {
System.out.println("\n--- Map 选择指南 ---");
// 场景1:一般用途,高性能
System.out.println("场景1:一般用途,高性能 -> 选择HashMap");
Map<String, Integer> hashMap = new HashMap<>();
// 场景2:需要保持插入顺序
System.out.println("场景2:保持插入顺序 -> 选择LinkedHashMap");
Map<String, Integer> linkedHashMap = new LinkedHashMap<>();
// 场景3:需要排序
System.out.println("场景3:需要排序 -> 选择TreeMap");
Map<String, Integer> treeMap = new TreeMap<>();
// 场景4:线程安全
System.out.println("场景4:线程安全 -> 选择ConcurrentHashMap");
// Map<String, Integer> concurrentMap = new ConcurrentHashMap<>();
// 场景5:枚举键
System.out.println("场景5:枚举键 -> 选择EnumMap");
Map<DayOfWeek, String> enumMap = new EnumMap<>(DayOfWeek.class);
}
public static void demonstrateQueueSelection() {
System.out.println("\n--- Queue 选择指南 ---");
// 场景1:FIFO队列
System.out.println("场景1:FIFO队列 -> 选择LinkedList或ArrayDeque");
Queue<String> fifoQueue = new LinkedList<>();
Queue<String> arrayDeque = new ArrayDeque<>();
// 场景2:优先级队列
System.out.println("场景2:优先级队列 -> 选择PriorityQueue");
Queue<Integer> priorityQueue = new PriorityQueue<>();
// 场景3:双端队列
System.out.println("场景3:双端队列 -> 选择ArrayDeque");
Deque<String> deque = new ArrayDeque<>();
}
public static void performanceComparison() {
System.out.println("\n--- 性能对比 ---");
int size = 100000;
// List 性能对比
System.out.println("\nList 添加性能对比(在末尾添加):");
testListAddPerformance(new ArrayList<>(), "ArrayList", size);
testListAddPerformance(new LinkedList<>(), "LinkedList", size);
testListAddPerformance(new Vector<>(), "Vector", size);
// Set 性能对比
System.out.println("\nSet 添加性能对比:");
testSetAddPerformance(new HashSet<>(), "HashSet", size);
testSetAddPerformance(new LinkedHashSet<>(), "LinkedHashSet", size);
testSetAddPerformance(new TreeSet<>(), "TreeSet", size);
// Map 性能对比
System.out.println("\nMap 添加性能对比:");
testMapPutPerformance(new HashMap<>(), "HashMap", size);
testMapPutPerformance(new LinkedHashMap<>(), "LinkedHashMap", size);
testMapPutPerformance(new TreeMap<>(), "TreeMap", size);
}
private static void testListAddPerformance(List<Integer> list, String name, int size) {
long startTime = System.nanoTime();
for (int i = 0; i < size; i++) {
list.add(i);
}
long endTime = System.nanoTime();
System.out.println(name + ": " + (endTime - startTime) / 1000000 + "ms");
}
private static void testSetAddPerformance(Set<Integer> set, String name, int size) {
long startTime = System.nanoTime();
for (int i = 0; i < size; i++) {
set.add(i);
}
long endTime = System.nanoTime();
System.out.println(name + ": " + (endTime - startTime) / 1000000 + "ms");
}
private static void testMapPutPerformance(Map<Integer, String> map, String name, int size) {
long startTime = System.nanoTime();
for (int i = 0; i < size; i++) {
map.put(i, "Value" + i);
}
long endTime = System.nanoTime();
System.out.println(name + ": " + (endTime - startTime) / 1000000 + "ms");
}
}
// 示例枚举
enum DayOfWeek {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
5.2 集合选择决策表
public class CollectionDecisionTable {
public static void main(String[] args) {
printCollectionDecisionTable();
}
public static void printCollectionDecisionTable() {
System.out.println("=== 集合选择决策表 ===");
System.out.println("\n【List 选择】");
System.out.println("需求场景 | 推荐选择 | 时间复杂度 | 说明");
System.out.println("---------------------------|---------------|-------------|------------------");
System.out.println("频繁随机访问 | ArrayList | get: O(1) | 基于数组实现");
System.out.println("频繁在开头/中间插入删除 | LinkedList | add: O(1)* | 基于链表实现");
System.out.println("需要线程安全 | Vector | 同ArrayList | 同步方法");
System.out.println("读多写少的并发场景 | CopyOnWrite | read: O(1) | 写时复制");
System.out.println("\n【Set 选择】");
System.out.println("需求场景 | 推荐选择 | 时间复杂度 | 说明");
System.out.println("---------------------------|---------------|-------------|------------------");
System.out.println("快速查找,无序要求 | HashSet | O(1) | 基于哈希表");
System.out.println("保持插入顺序 | LinkedHashSet | O(1) | 哈希表+链表");
System.out.println("需要排序 | TreeSet | O(log n) | 基于红黑树");
System.out.println("枚举类型 | EnumSet | O(1) | 位向量实现");
System.out.println("\n【Map 选择】");
System.out.println("需求场景 | 推荐选择 | 时间复杂度 | 说明");
System.out.println("---------------------------|---------------|-------------|------------------");
System.out.println("一般用途,高性能 | HashMap | O(1) | 基于哈希表");
System.out.println("保持插入顺序 | LinkedHashMap | O(1) | 哈希表+链表");
System.out.println("需要排序 | TreeMap | O(log n) | 基于红黑树");
System.out.println("线程安全 | ConcurrentMap | O(1) | 分段锁");
System.out.println("枚举键 | EnumMap | O(1) | 数组实现");
System.out.println("\n【Queue 选择】");
System.out.println("需求场景 | 推荐选择 | 时间复杂度 | 说明");
System.out.println("---------------------------|---------------|-------------|------------------");
System.out.println("FIFO队列 | ArrayDeque | O(1) | 循环数组");
System.out.println("双端队列 | ArrayDeque | O(1) | 两端操作");
System.out.println("优先级队列 | PriorityQueue | O(log n) | 基于堆");
System.out.println("线程安全队列 | BlockingQueue | varies | 阻塞队列");
System.out.println("\n【内存使用对比】");
System.out.println("集合类型 | 内存开销 | 说明");
System.out.println("---------------|-----------|---------------------------");
System.out.println("ArrayList | 低 | 只存储元素数组");
System.out.println("LinkedList | 高 | 每个节点额外存储前后指针");
System.out.println("HashSet | 中 | 基于HashMap实现");
System.out.println("TreeSet | 中 | 红黑树节点开销");
System.out.println("HashMap | 中 | 哈希表+链表/红黑树");
System.out.println("TreeMap | 高 | 红黑树节点开销较大");
}
}
六、集合遍历方法
6.1 传统遍历方式
import java.util.*;
public class CollectionIterationDemo {
public static void main(String[] args) {
System.out.println("=== 集合遍历方法 ===");
// List 遍历
demonstrateListIteration();
// Set 遍历
demonstrateSetIteration();
// Map 遍历
demonstrateMapIteration();
// Iterator 的高级用法
demonstrateIteratorAdvanced();
}
public static void demonstrateListIteration() {
System.out.println("\n--- List 遍历方式 ---");
List<String> list = Arrays.asList("Apple", "Banana", "Cherry", "Date");
// 1. 传统for循环
System.out.println("1. 传统for循环:");
for (int i = 0; i < list.size(); i++) {
System.out.println("Index " + i + ": " + list.get(i));
}
// 2. 增强for循环(for-each)
System.out.println("\n2. 增强for循环:");
for (String item : list) {
System.out.println("Item: " + item);
}
// 3. Iterator
System.out.println("\n3. Iterator:");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println("Item: " + item);
}
// 4. ListIterator(双向遍历)
System.out.println("\n4. ListIterator(反向遍历):");
ListIterator<String> listIterator = list.listIterator(list.size());
while (listIterator.hasPrevious()) {
String item = listIterator.previous();
System.out.println("Item: " + item);
}
// 5. Stream API(Java 8+)
System.out.println("\n5. Stream API:");
list.stream().forEach(item -> System.out.println("Item: " + item));
}
public static void demonstrateSetIteration() {
System.out.println("\n--- Set 遍历方式 ---");
Set<String> set = new HashSet<>(Arrays.asList("Apple", "Banana", "Cherry", "Date"));
// 1. 增强for循环
System.out.println("1. 增强for循环:");
for (String item : set) {
System.out.println("Item: " + item);
}
// 2. Iterator
System.out.println("\n2. Iterator:");
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println("Item: " + item);
}
// 3. Stream API
System.out.println("\n3. Stream API:");
set.stream().forEach(item -> System.out.println("Item: " + item));
// 4. 过滤遍历
System.out.println("\n4. 过滤遍历(以A开头):");
set.stream()
.filter(item -> item.startsWith("A"))
.forEach(item -> System.out.println("Filtered: " + item));
}
public static void demonstrateMapIteration() {
System.out.println("\n--- Map 遍历方式 ---");
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 10);
map.put("Banana", 20);
map.put("Cherry", 15);
map.put("Date", 25);
// 1. 遍历键
System.out.println("1. 遍历键:");
for (String key : map.keySet()) {
System.out.println("Key: " + key + ", Value: " + map.get(key));
}
// 2. 遍历值
System.out.println("\n2. 遍历值:");
for (Integer value : map.values()) {
System.out.println("Value: " + value);
}
// 3. 遍历键值对
System.out.println("\n3. 遍历键值对:");
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
// 4. 使用Iterator遍历键值对
System.out.println("\n4. 使用Iterator遍历键值对:");
Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Integer> entry = iterator.next();
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
// 5. Lambda表达式(Java 8+)
System.out.println("\n5. Lambda表达式:");
map.forEach((key, value) -> System.out.println(key + " -> " + value));
// 6. Stream API 复杂操作
System.out.println("\n6. Stream API 复杂操作(值大于15):");
map.entrySet().stream()
.filter(entry -> entry.getValue() > 15)
.sorted(Map.Entry.comparingByValue())
.forEach(entry -> System.out.println(entry.getKey() + ": " + entry.getValue()));
}
public static void demonstrateIteratorAdvanced() {
System.out.println("\n--- Iterator 高级用法 ---");
// 安全删除元素
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));
System.out.println("原列表: " + list);
// 错误的删除方式(会抛出ConcurrentModificationException)
// for (String item : list) {
// if (item.equals("C")) {
// list.remove(item); // 错误!
// }
// }
// 正确的删除方式
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (item.equals("C")) {
iterator.remove(); // 正确!
}
}
System.out.println("删除C后: " + list);
// ListIterator 的双向遍历和修改
List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
System.out.println("\n原数字列表: " + numbers);
ListIterator<Integer> listIterator = numbers.listIterator();
while (listIterator.hasNext()) {
Integer num = listIterator.next();
if (num % 2 == 0) {
listIterator.set(num * 10); // 偶数乘以10
}
if (num == 3) {
listIterator.add(99); // 在3后面添加99
}
}
System.out.println("修改后: " + numbers);
// 反向遍历
System.out.println("\n反向遍历:");
while (listIterator.hasPrevious()) {
System.out.println("Previous: " + listIterator.previous());
}
}
}
总结
Java 集合框架是 Java 编程的核心组件,掌握其使用方法和最佳实践对于编写高效、可维护的代码至关重要。
关键要点
- 选择合适的集合类型:根据具体需求选择 List、Set、Map 或 Queue
- 性能考虑:了解不同实现的时间复杂度和适用场景
- 线程安全:在多线程环境中选择合适的并发集合
- 内存优化:合理设置初始容量,避免频繁扩容
- 遍历方式:选择合适的遍历方法,善用 Stream API
- 避免陷阱:注意 equals/hashCode 的重写,避免在遍历时修改集合
通过深入理解和实践这些概念,你将能够更好地利用 Java 集合框架来解决实际编程问题。