Java 集合框架
Java集合框架是Java编程语言中用来表示和操作集合的统一架构。它包含接口、实现类和算法,使得程序员可以高效地处理数据集合。
异常处理
异常体系结构
Java的异常处理机制是程序设计中的重要组成部分,它允许程序优雅地处理运行时错误。
java
// 异常层次结构
// Throwable
// ├── Error (系统错误,通常不处理)
// │ ├── OutOfMemoryError
// │ ├── StackOverflowError
// │ └── ...
// └── Exception (程序异常,可以处理)
// ├── RuntimeException (运行时异常,非检查异常)
// │ ├── NullPointerException
// │ ├── ArrayIndexOutOfBoundsException
// │ ├── IllegalArgumentException
// │ └── ...
// └── CheckedException (检查异常,必须处理)
// ├── IOException
// ├── SQLException
// └── ...
// 自定义异常类
class CustomException extends Exception {
public CustomException(String message) {
super(message);
}
public CustomException(String message, Throwable cause) {
super(message, cause);
}
}
// 业务异常类
class BusinessException extends RuntimeException {
private int errorCode;
public BusinessException(int errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public int getErrorCode() {
return errorCode;
}
}
// 异常处理示例
public class ExceptionHandlingExample {
public static void main(String[] args) {
System.out.println("=== 异常处理示例 ===");
// 1. 基本异常处理
try {
int result = divide(10, 0);
System.out.println("结果: " + result);
} catch (ArithmeticException e) {
System.out.println("捕获到算术异常: " + e.getMessage());
}
// 2. 多重异常处理
try {
processArray(new int[]{1, 2, 3}, 5);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界异常: " + e.getMessage());
} catch (IllegalArgumentException e) {
System.out.println("非法参数异常: " + e.getMessage());
} catch (Exception e) {
System.out.println("其他异常: " + e.getMessage());
} finally {
System.out.println("finally块总是执行");
}
// 3. 自定义异常处理
try {
validateAge(-5);
} catch (CustomException e) {
System.out.println("自定义异常: " + e.getMessage());
}
// 4. 运行时异常处理
try {
String str = null;
int length = str.length(); // 会抛出NullPointerException
} catch (NullPointerException e) {
System.out.println("空指针异常: " + e.getMessage());
}
// 5. 检查异常处理
try {
readFile("nonexistent.txt");
} catch (java.io.IOException e) {
System.out.println("IO异常: " + e.getMessage());
}
// 6. 异常链
try {
processBusinessData();
} catch (BusinessException e) {
System.out.println("业务异常 [错误码: " + e.getErrorCode() + "]: " + e.getMessage());
if (e.getCause() != null) {
System.out.println("原因: " + e.getCause().getMessage());
}
}
}
// 可能抛出算术异常的方法
public static int divide(int a, int b) {
return a / b; // 当b为0时抛出ArithmeticException
}
// 可能抛出多种异常的方法
public static void processArray(int[] array, int index) {
if (array == null) {
throw new IllegalArgumentException("数组不能为null");
}
if (index < 0) {
throw new IllegalArgumentException("索引不能为负数");
}
System.out.println("数组元素: " + array[index]);
}
// 抛出自定义异常的方法
public static void validateAge(int age) throws CustomException {
if (age < 0) {
throw new CustomException("年龄不能为负数: " + age);
}
if (age > 150) {
throw new CustomException("年龄不能超过150: " + age);
}
System.out.println("有效年龄: " + age);
}
// 抛出检查异常的方法
public static void readFile(String filename) throws java.io.IOException {
java.io.File file = new java.io.File(filename);
if (!file.exists()) {
throw new java.io.IOException("文件不存在: " + filename);
}
// 实际的文件读取逻辑...
System.out.println("文件读取成功: " + filename);
}
// 业务处理方法,演示异常链
public static void processBusinessData() throws BusinessException {
try {
// 模拟数据库操作
performDatabaseOperation();
} catch (java.sql.SQLException e) {
// 将SQLException包装为BusinessException
throw new BusinessException(1001, "数据库操作失败") {{
initCause(e);
}};
}
}
// 模拟数据库操作
public static void performDatabaseOperation() throws java.sql.SQLException {
// 模拟数据库连接失败
throw new java.sql.SQLException("数据库连接失败");
}
}try-catch-finally 语句
try-catch-finally是Java中处理异常的基本结构,用于捕获和处理异常。
java
// 资源管理类
class ResourceManager {
private boolean isOpen = false;
public void open() {
isOpen = true;
System.out.println("资源已打开");
}
public void close() {
if (isOpen) {
isOpen = false;
System.out.println("资源已关闭");
}
}
public void useResource() throws Exception {
if (!isOpen) {
throw new Exception("资源未打开");
}
System.out.println("正在使用资源");
// 模拟使用过程中可能发生的异常
if (Math.random() > 0.7) {
throw new Exception("资源使用过程中发生错误");
}
}
}
// try-catch-finally示例
public class TryCatchFinallyExample {
public static void main(String[] args) {
System.out.println("=== try-catch-finally 示例 ===");
// 1. 基本的try-catch-finally
basicTryCatchFinally();
// 2. 多重catch块
multipleCatchBlocks();
// 3. try-with-resources (Java 7+)
tryWithResources();
// 4. 嵌套的try-catch
nestedTryCatch();
// 5. 异常在finally中的处理
exceptionInFinally();
}
// 基本的try-catch-finally
public static void basicTryCatchFinally() {
System.out.println("\n--- 基本try-catch-finally ---");
ResourceManager resource = new ResourceManager();
try {
resource.open();
resource.useResource();
System.out.println("资源使用成功");
} catch (Exception e) {
System.out.println("捕获异常: " + e.getMessage());
} finally {
resource.close();
System.out.println("finally块执行完毕");
}
}
// 多重catch块
public static void multipleCatchBlocks() {
System.out.println("\n--- 多重catch块 ---");
int[] numbers = {1, 2, 3};
try {
// 可能抛出多种异常的代码
int index = Integer.parseInt("abc"); // NumberFormatException
System.out.println(numbers[index]); // ArrayIndexOutOfBoundsException
} catch (NumberFormatException e) {
System.out.println("数字格式异常: " + e.getMessage());
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界异常: " + e.getMessage());
} catch (Exception e) {
System.out.println("其他异常: " + e.getMessage());
} finally {
System.out.println("多重catch示例完成");
}
}
// try-with-resources (Java 7+)
public static void tryWithResources() {
System.out.println("\n--- try-with-resources ---");
// 使用try-with-resources自动管理资源
try (java.io.FileWriter writer = new java.io.FileWriter("example.txt");
java.io.PrintWriter printWriter = new java.io.PrintWriter(writer)) {
printWriter.println("Hello, World!");
printWriter.println("这是try-with-resources示例");
// 模拟可能的异常
if (Math.random() > 0.8) {
throw new Exception("写入过程中发生错误");
}
} catch (Exception e) {
System.out.println("捕获异常: " + e.getMessage());
} finally {
System.out.println("try-with-resources示例完成");
}
// 读取文件验证
try (java.io.BufferedReader reader = java.nio.file.Files.newBufferedReader(
java.nio.file.Paths.get("example.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println("读取到: " + line);
}
} catch (Exception e) {
System.out.println("读取文件异常: " + e.getMessage());
}
}
// 嵌套的try-catch
public static void nestedTryCatch() {
System.out.println("\n--- 嵌套try-catch ---");
try {
System.out.println("外层try块开始");
try {
System.out.println("内层try块开始");
int result = 10 / 0; // 会抛出ArithmeticException
System.out.println("内层try块结束");
} catch (ArithmeticException e) {
System.out.println("内层catch块: " + e.getMessage());
// 重新抛出异常
throw new RuntimeException("内层异常重新抛出", e);
} finally {
System.out.println("内层finally块执行");
}
System.out.println("外层try块结束");
} catch (RuntimeException e) {
System.out.println("外层catch块: " + e.getMessage());
if (e.getCause() != null) {
System.out.println("原因: " + e.getCause().getMessage());
}
} finally {
System.out.println("外层finally块执行");
}
}
// 异常在finally中的处理
public static void exceptionInFinally() {
System.out.println("\n--- finally中的异常 ---");
try {
System.out.println("try块执行");
throw new Exception("try块中的异常");
} catch (Exception e) {
System.out.println("catch块: " + e.getMessage());
} finally {
System.out.println("finally块执行");
// finally块中的异常会抑制try块中的异常
try {
throw new RuntimeException("finally块中的异常");
} catch (RuntimeException e) {
System.out.println("finally中异常被捕获: " + e.getMessage());
}
}
}
}
// 自定义资源类,实现AutoCloseable接口
class CustomResource implements AutoCloseable {
private String name;
private boolean closed = false;
public CustomResource(String name) {
this.name = name;
System.out.println("创建资源: " + name);
}
public void doWork() throws Exception {
if (closed) {
throw new Exception("资源已关闭,无法工作");
}
System.out.println("资源 " + name + " 正在工作");
// 模拟工作过程中可能发生的异常
if (Math.random() > 0.7) {
throw new Exception("资源 " + name + " 工作过程中发生错误");
}
}
@Override
public void close() throws Exception {
if (!closed) {
closed = true;
System.out.println("关闭资源: " + name);
// 模拟关闭过程中可能发生的异常
if (Math.random() > 0.8) {
throw new Exception("关闭资源 " + name + " 时发生错误");
}
}
}
}
// try-with-resources的高级示例
public class AdvancedTryWithResources {
public static void main(String[] args) {
System.out.println("=== 高级try-with-resources示例 ===");
// 1. 多个资源
multipleResources();
// 2. 自定义资源
customResource();
// 3. 资源关闭顺序
resourceClosingOrder();
}
// 多个资源
public static void multipleResources() {
System.out.println("\n--- 多个资源 ---");
try (java.io.FileInputStream fis = new java.io.FileInputStream("input.txt");
java.io.FileOutputStream fos = new java.io.FileOutputStream("output.txt");
java.io.BufferedInputStream bis = new java.io.BufferedInputStream(fis);
java.io.BufferedOutputStream bos = new java.io.BufferedOutputStream(fos)) {
// 复制文件
int data;
while ((data = bis.read()) != -1) {
bos.write(data);
}
System.out.println("文件复制完成");
} catch (java.io.IOException e) {
System.out.println("IO异常: " + e.getMessage());
}
}
// 自定义资源
public static void customResource() {
System.out.println("\n--- 自定义资源 ---");
try (CustomResource resource1 = new CustomResource("资源1");
CustomResource resource2 = new CustomResource("资源2")) {
resource1.doWork();
resource2.doWork();
} catch (Exception e) {
System.out.println("异常: " + e.getMessage());
if (e.getCause() != null) {
System.out.println("原因: " + e.getCause().getMessage());
}
}
}
// 资源关闭顺序
public static void resourceClosingOrder() {
System.out.println("\n--- 资源关闭顺序 ---");
// 资源按照声明的相反顺序关闭
try (FirstResource first = new FirstResource();
SecondResource second = new SecondResource();
ThirdResource third = new ThirdResource()) {
System.out.println("所有资源已创建并使用");
} catch (Exception e) {
System.out.println("异常: " + e.getMessage());
}
}
}
// 演示资源关闭顺序的类
class FirstResource implements AutoCloseable {
public FirstResource() {
System.out.println("创建FirstResource");
}
@Override
public void close() throws Exception {
System.out.println("关闭FirstResource");
}
}
class SecondResource implements AutoCloseable {
public SecondResource() {
System.out.println("创建SecondResource");
}
@Override
public void close() throws Exception {
System.out.println("关闭SecondResource");
}
}
class ThirdResource implements AutoCloseable {
public ThirdResource() {
System.out.println("创建ThirdResource");
}
@Override
public void close() throws Exception {
System.out.println("关闭ThirdResource");
}
}throws 与 throw 关键字
throws关键字用于声明方法可能抛出的异常,而throw关键字用于主动抛出异常。
java
// 自定义检查异常
class InsufficientFundsException extends Exception {
private double amount;
public InsufficientFundsException(double amount) {
super("余额不足,缺少金额: " + amount);
this.amount = amount;
}
public double getAmount() {
return amount;
}
}
// 自定义运行时异常
class InvalidAccountException extends RuntimeException {
public InvalidAccountException(String message) {
super(message);
}
}
// 银行账户类
class BankAccount {
private String accountNumber;
private double balance;
private String ownerName;
public BankAccount(String accountNumber, String ownerName, double initialBalance) {
this.accountNumber = accountNumber;
this.ownerName = ownerName;
this.balance = initialBalance;
}
// 存款方法 - 不会抛出检查异常
public void deposit(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("存款金额必须大于0");
}
balance += amount;
System.out.println("存款成功,当前余额: " + balance);
}
// 取款方法 - 声明可能抛出检查异常
public void withdraw(double amount) throws InsufficientFundsException {
if (amount <= 0) {
throw new IllegalArgumentException("取款金额必须大于0");
}
if (amount > balance) {
// 抛出自定义检查异常
throw new InsufficientFundsException(amount - balance);
}
balance -= amount;
System.out.println("取款成功,当前余额: " + balance);
}
// 转账方法 - 声明可能抛出多种异常
public void transfer(BankAccount targetAccount, double amount)
throws InsufficientFundsException, InvalidAccountException {
if (targetAccount == null) {
// 抛出自定义运行时异常
throw new InvalidAccountException("目标账户不能为空");
}
if (amount <= 0) {
throw new IllegalArgumentException("转账金额必须大于0");
}
// 先检查余额
if (amount > balance) {
throw new InsufficientFundsException(amount - balance);
}
// 执行转账
this.withdraw(amount);
targetAccount.deposit(amount);
System.out.println("转账成功,从 " + this.accountNumber + " 转到 " + targetAccount.accountNumber);
}
// 验证账户有效性 - 可能抛出运行时异常
public void validateAccount() throws InvalidAccountException {
if (accountNumber == null || accountNumber.isEmpty()) {
throw new InvalidAccountException("账户号码无效");
}
if (ownerName == null || ownerName.isEmpty()) {
throw new InvalidAccountException("账户持有人姓名无效");
}
System.out.println("账户验证通过: " + accountNumber);
}
// 重置账户 - 演示异常链
public void resetAccount() throws InsufficientFundsException {
try {
// 模拟复杂的重置操作
performComplexOperation();
} catch (Exception e) {
// 将其他异常包装为业务异常
InsufficientFundsException businessEx =
new InsufficientFundsException(0);
businessEx.initCause(e);
throw businessEx;
}
}
// 模拟复杂操作
private void performComplexOperation() throws Exception {
// 模拟操作失败
if (Math.random() > 0.7) {
throw new Exception("复杂操作执行失败");
}
System.out.println("复杂操作执行成功");
}
// getter方法
public String getAccountNumber() {
return accountNumber;
}
public double getBalance() {
return balance;
}
public String getOwnerName() {
return ownerName;
}
}
// throws与throw关键字示例
public class ThrowsThrowExample {
public static void main(String[] args) {
System.out.println("=== throws与throw关键字示例 ===");
// 1. 基本的throws使用
basicThrowsUsage();
// 2. throw关键字使用
throwKeywordUsage();
// 3. 异常链演示
exceptionChaining();
// 4. 多重异常声明
multipleExceptionDeclaration();
// 5. 异常处理最佳实践
exceptionBestPractices();
}
// 基本的throws使用
public static void basicThrowsUsage() {
System.out.println("\n--- 基本throws使用 ---");
BankAccount account = new BankAccount("123456", "张三", 1000.0);
try {
// 调用声明throws的方法
account.withdraw(500.0);
System.out.println("取款500成功");
} catch (InsufficientFundsException e) {
System.out.println("取款失败: " + e.getMessage());
System.out.println("缺少金额: " + e.getAmount());
}
try {
// 尝试取款超过余额
account.withdraw(1500.0);
} catch (InsufficientFundsException e) {
System.out.println("取款失败: " + e.getMessage());
System.out.println("缺少金额: " + e.getAmount());
}
}
// throw关键字使用
public static void throwKeywordUsage() {
System.out.println("\n--- throw关键字使用 ---");
BankAccount account = new BankAccount("789012", "李四", 2000.0);
try {
// 正常存款
account.deposit(500.0);
// 尝试存入负数(会抛出运行时异常)
account.deposit(-100.0);
} catch (IllegalArgumentException e) {
System.out.println("存款异常: " + e.getMessage());
}
try {
// 验证账户
account.validateAccount();
// 创建无效账户并验证(会抛出运行时异常)
BankAccount invalidAccount = new BankAccount("", "", 0);
invalidAccount.validateAccount();
} catch (InvalidAccountException e) {
System.out.println("账户验证异常: " + e.getMessage());
}
}
// 异常链演示
public static void exceptionChaining() {
System.out.println("\n--- 异常链演示 ---");
BankAccount account = new BankAccount("345678", "王五", 1500.0);
try {
// 调用会引发异常链的方法
account.resetAccount();
} catch (InsufficientFundsException e) {
System.out.println("业务异常: " + e.getMessage());
if (e.getCause() != null) {
System.out.println("根本原因: " + e.getCause().getMessage());
}
}
}
// 多重异常声明
public static void multipleExceptionDeclaration() {
System.out.println("\n--- 多重异常声明 ---");
BankAccount sourceAccount = new BankAccount("111111", "赵六", 3000.0);
BankAccount targetAccount = new BankAccount("222222", "钱七", 500.0);
try {
// 正常转账
sourceAccount.transfer(targetAccount, 1000.0);
System.out.println("转账成功");
} catch (InsufficientFundsException e) {
System.out.println("余额不足: " + e.getMessage());
} catch (InvalidAccountException e) {
System.out.println("账户无效: " + e.getMessage());
}
try {
// 转账到null账户
sourceAccount.transfer(null, 500.0);
} catch (InsufficientFundsException | InvalidAccountException e) {
// Java 7+ 多重catch
System.out.println("转账异常: " + e.getMessage());
}
try {
// 余额不足转账
sourceAccount.transfer(targetAccount, 5000.0);
} catch (InsufficientFundsException e) {
System.out.println("转账失败 - " + e.getMessage());
} catch (InvalidAccountException e) {
System.out.println("转账失败 - " + e.getMessage());
}
}
// 异常处理最佳实践
public static void exceptionBestPractices() {
System.out.println("\n--- 异常处理最佳实践 ---");
BankAccount account = new BankAccount("999999", "孙八", 100.0);
// 1. 具体异常优于通用异常
try {
account.deposit(-50.0);
} catch (IllegalArgumentException e) {
System.out.println("具体异常处理: " + e.getMessage());
}
// 2. 早期检查,快速失败
try {
if (account.getBalance() < 200.0) {
throw new InsufficientFundsException(200.0 - account.getBalance());
}
System.out.println("余额充足,可以进行操作");
} catch (InsufficientFundsException e) {
System.out.println("预检查失败: " + e.getMessage());
}
// 3. 异常信息要详细
try {
account.transfer(null, 100.0);
} catch (InvalidAccountException e) {
System.out.println("详细异常信息: " + e.getMessage() +
" [操作类型: 转账, 操作账户: " + account.getAccountNumber() + "]");
} catch (InsufficientFundsException e) {
System.out.println("详细异常信息: " + e.getMessage() +
" [操作类型: 转账, 操作账户: " + account.getAccountNumber() +
", 缺少金额: " + e.getAmount() + "]");
}
}
}
// 异常处理工具类
class ExceptionUtils {
// 包装检查异常为运行时异常
public static <T> T unchecked(java.util.concurrent.Callable<T> callable) {
try {
return callable.call();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// 包装Runnable中的检查异常
public static void unchecked(java.lang.Runnable runnable) {
try {
runnable.run();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// 获取异常的根原因
public static Throwable getRootCause(Throwable throwable) {
Throwable cause = throwable;
while (cause.getCause() != null) {
cause = cause.getCause();
}
return cause;
}
// 打印完整的异常链
public static void printExceptionChain(Throwable throwable) {
System.out.println("异常链:");
Throwable cause = throwable;
int level = 0;
while (cause != null) {
for (int i = 0; i < level; i++) {
System.out.print(" ");
}
System.out.println(cause.getClass().getSimpleName() + ": " + cause.getMessage());
cause = cause.getCause();
level++;
}
}
}
// 异常工具类使用示例
public class ExceptionUtilsExample {
public static void main(String[] args) {
System.out.println("=== 异常工具类使用示例 ===");
// 1. 包装检查异常
try {
String content = ExceptionUtils.unchecked(() -> {
return java.nio.file.Files.readString(
java.nio.file.Paths.get("nonexistent.txt"));
});
System.out.println("文件内容: " + content);
} catch (RuntimeException e) {
System.out.println("包装的异常: " + e.getMessage());
ExceptionUtils.printExceptionChain(e);
}
// 2. 获取根原因
try {
BankAccount account = new BankAccount("123", "测试", 100);
account.resetAccount();
} catch (InsufficientFundsException e) {
Throwable rootCause = ExceptionUtils.getRootCause(e);
System.out.println("根原因: " + rootCause.getClass().getSimpleName() +
": " + rootCause.getMessage());
}
}
}集合框架进阶
HashMap 与 HashSet 原理
HashMap和HashSet是Java集合框架中最重要的类之一,理解它们的内部实现原理对于高效使用它们至关重要。
java
import java.util.*;
// 简化版HashMap实现,用于演示原理
class SimpleHashMap<K, V> {
// 默认初始容量
private static final int DEFAULT_CAPACITY = 16;
// 负载因子
private static final float LOAD_FACTOR = 0.75f;
// Entry节点类
static class Entry<K, V> {
K key;
V value;
Entry<K, V> next;
int hash;
Entry(int hash, K key, V value, Entry<K, V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
}
// 存储桶数组
private Entry<K, V>[] table;
// 实际存储的键值对数量
private int size;
// 阈值,当size超过此值时需要扩容
private int threshold;
// 构造方法
@SuppressWarnings("unchecked")
public SimpleHashMap() {
table = new Entry[DEFAULT_CAPACITY];
threshold = (int) (DEFAULT_CAPACITY * LOAD_FACTOR);
}
// 简单的哈希函数
private int hash(Object key) {
if (key == null) {
return 0;
}
int h = key.hashCode();
// 扰动函数,减少哈希冲突
return h ^ (h >>> 16);
}
// 计算数组索引
private int indexFor(int hash, int length) {
return hash & (length - 1);
}
// 获取值
public V get(Object key) {
int hash = hash(key);
int index = indexFor(hash, table.length);
for (Entry<K, V> e = table[index]; e != null; e = e.next) {
if (e.hash == hash && (e.key == key || (key != null && key.equals(e.key)))) {
return e.value;
}
}
return null;
}
// 存储键值对
public V put(K key, V value) {
// 检查是否需要扩容
if (size >= threshold) {
resize();
}
int hash = hash(key);
int index = indexFor(hash, table.length);
// 遍历链表查找是否已存在该key
for (Entry<K, V> e = table[index]; e != null; e = e.next) {
if (e.hash == hash && (e.key == key || (key != null && key.equals(e.key)))) {
V oldValue = e.value;
e.value = value;
return oldValue;
}
}
// 不存在则添加新节点
addEntry(hash, key, value, index);
return null;
}
// 添加新节点
private void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K, V> entry = table[bucketIndex];
table[bucketIndex] = new Entry<>(hash, key, value, entry);
size++;
}
// 扩容
@SuppressWarnings("unchecked")
private void resize() {
Entry<K, V>[] oldTable = table;
int oldCapacity = oldTable.length;
int newCapacity = oldCapacity << 1; // 扩大一倍
// 创建新数组
Entry<K, V>[] newTable = new Entry[newCapacity];
// 重新哈希所有元素
transfer(newTable);
table = newTable;
threshold = (int) (newCapacity * LOAD_FACTOR);
}
// 转移元素到新数组
private void transfer(Entry<K, V>[] newTable) {
Entry<K, V>[] src = table;
int newCapacity = newTable.length;
for (int j = 0; j < src.length; j++) {
Entry<K, V> e = src[j];
if (e != null) {
src[j] = null;
do {
Entry<K, V> next = e.next;
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);
}
}
}
// 获取大小
public int size() {
return size;
}
// 检查是否为空
public boolean isEmpty() {
return size == 0;
}
// 移除键值对
public V remove(Object key) {
int hash = hash(key);
int index = indexFor(hash, table.length);
Entry<K, V> prev = table[index];
Entry<K, V> e = prev;
while (e != null) {
Entry<K, V> next = e.next;
if (e.hash == hash && (e.key == key || (key != null && key.equals(e.key)))) {
size--;
if (prev == e) {
table[index] = next;
} else {
prev.next = next;
}
return e.value;
}
prev = e;
e = next;
}
return null;
}
}
// HashMap原理演示
public class HashMapPrinciple {
public static void main(String[] args) {
System.out.println("=== HashMap原理演示 ===");
// 1. 基本操作演示
basicOperations();
// 2. 哈希冲突演示
hashCollision();
// 3. 扩容演示
resizeDemo();
// 4. 性能比较
performanceComparison();
// 5. 线程安全问题
threadSafetyIssue();
}
// 基本操作演示
public static void basicOperations() {
System.out.println("\n--- 基本操作演示 ---");
// 使用Java内置HashMap
Map<String, Integer> map = new HashMap<>();
// 添加元素
map.put("apple", 10);
map.put("banana", 20);
map.put("orange", 30);
System.out.println("添加元素后: " + map);
System.out.println("大小: " + map.size());
// 获取元素
System.out.println("apple的数量: " + map.get("apple"));
System.out.println("grape的数量: " + map.get("grape")); // 返回null
// 检查键是否存在
System.out.println("是否包含apple键: " + map.containsKey("apple"));
System.out.println("是否包含grape键: " + map.containsKey("grape"));
// 检查值是否存在
System.out.println("是否包含值20: " + map.containsValue(20));
// 更新元素
map.put("apple", 15);
System.out.println("更新apple后: " + map);
// 移除元素
Integer removedValue = map.remove("banana");
System.out.println("移除banana: " + removedValue);
System.out.println("移除后: " + map);
// 遍历HashMap
System.out.println("遍历键值对:");
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
}
// 哈希冲突演示
public static void hashCollision() {
System.out.println("\n--- 哈希冲突演示 ---");
// 创建会哈希冲突的键
class BadHashKey {
private String value;
public BadHashKey(String value) {
this.value = value;
}
@Override
public int hashCode() {
// 故意返回相同的哈希码,制造哈希冲突
return 1;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
BadHashKey that = (BadHashKey) obj;
return Objects.equals(value, that.value);
}
@Override
public String toString() {
return "BadHashKey{" + value + "}";
}
}
Map<BadHashKey, String> map = new HashMap<>();
// 添加多个键值对,它们会有相同的哈希码
for (int i = 0; i < 5; i++) {
map.put(new BadHashKey("key" + i), "value" + i);
}
System.out.println("哈希冲突的Map: " + map);
System.out.println("大小: " + map.size());
// 查看性能影响
long startTime = System.nanoTime();
for (int i = 0; i < 1000; i++) {
map.get(new BadHashKey("key" + (i % 5)));
}
long endTime = System.nanoTime();
System.out.println("1000次查找耗时: " + (endTime - startTime) / 1000000.0 + " ms");
}
// 扩容演示
public static void resizeDemo() {
System.out.println("\n--- 扩容演示 ---");
// 创建初始容量为4的HashMap
Map<Integer, String> map = new HashMap<>(4);
System.out.println("初始容量: " + getCapacity(map));
// 添加元素观察扩容
for (int i = 0; i < 15; i++) {
map.put(i, "value" + i);
if (i == 3 || i == 6 || i == 12) {
System.out.println("添加" + (i + 1) + "个元素后,容量: " + getCapacity(map));
}
}
System.out.println("最终大小: " + map.size());
System.out.println("最终容量: " + getCapacity(map));
}
// 获取HashMap的容量(通过反射)
private static int getCapacity(Map<?, ?> map) {
try {
Field tableField = HashMap.class.getDeclaredField("table");
tableField.setAccessible(true);
Object[] table = (Object[]) tableField.get(map);
return table == null ? 0 : table.length;
} catch (Exception e) {
return -1;
}
}
// 性能比较
public static void performanceComparison() {
System.out.println("\n--- 性能比较 ---");
int testSize = 100000;
// 测试HashMap性能
Map<Integer, String> hashMap = new HashMap<>();
long startTime = System.currentTimeMillis();
for (int i = 0; i < testSize; i++) {
hashMap.put(i, "value" + i);
}
long putTime = System.currentTimeMillis() - startTime;
startTime = System.currentTimeMillis();
for (int i = 0; i < testSize; i++) {
hashMap.get(i);
}
long getTime = System.currentTimeMillis() - startTime;
System.out.println("HashMap性能测试 (" + testSize + "元素):");
System.out.println(" 插入耗时: " + putTime + " ms");
System.out.println(" 查找耗时: " + getTime + " ms");
// 测试TreeMap性能(作为对比)
Map<Integer, String> treeMap = new TreeMap<>();
startTime = System.currentTimeMillis();
for (int i = 0; i < testSize; i++) {
treeMap.put(i, "value" + i);
}
long treePutTime = System.currentTimeMillis() - startTime;
startTime = System.currentTimeMillis();
for (int i = 0; i < testSize; i++) {
treeMap.get(i);
}
long treeGetTime = System.currentTimeMillis() - startTime;
System.out.println("TreeMap性能测试 (" + testSize + "元素):");
System.out.println(" 插入耗时: " + treePutTime + " ms");
System.out.println(" 查找耗时: " + treeGetTime + " ms");
}
// 线程安全问题演示
public static void threadSafetyIssue() {
System.out.println("\n--- 线程安全问题演示 ---");
final Map<String, Integer> map = new HashMap<>();
// 创建多个线程同时操作HashMap
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.length; i++) {
final int threadNum = i;
threads[i] = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
map.put("key" + threadNum + "_" + j, j);
map.get("key" + threadNum + "_" + (j - 1));
}
});
}
long startTime = System.currentTimeMillis();
// 启动所有线程
for (Thread thread : threads) {
thread.start();
}
// 等待所有线程完成
try {
for (Thread thread : threads) {
thread.join();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("多线程操作HashMap:");
System.out.println(" 期望大小: " + (10 * 1000));
System.out.println(" 实际大小: " + map.size());
System.out.println(" 耗时: " + (endTime - startTime) + " ms");
System.out.println(" 注意: 可能出现ConcurrentModificationException");
}
}
// HashSet原理演示
class HashSetPrinciple {
public static void main(String[] args) {
System.out.println("=== HashSet原理演示 ===");
// 1. HashSet基本操作
basicOperations();
// 2. HashSet与HashMap的关系
relationshipWithHashMap();
// 3. 自定义对象的HashSet使用
customObjectHashSet();
// 4. LinkedHashSet演示
linkedHashSetDemo();
}
// HashSet基本操作
public static void basicOperations() {
System.out.println("\n--- HashSet基本操作 ---");
Set<String> set = new HashSet<>();
// 添加元素
set.add("apple");
set.add("banana");
set.add("orange");
set.add("apple"); // 重复元素不会被添加
System.out.println("添加元素后: " + set);
System.out.println("大小: " + set.size());
// 检查元素是否存在
System.out.println("是否包含apple: " + set.contains("apple"));
System.out.println("是否包含grape: " + set.contains("grape"));
// 移除元素
boolean removed = set.remove("banana");
System.out.println("移除banana: " + removed);
System.out.println("移除后: " + set);
// 遍历HashSet
System.out.println("遍历元素:");
for (String fruit : set) {
System.out.println(" " + fruit);
}
}
// HashSet与HashMap的关系
public static void relationshipWithHashMap() {
System.out.println("\n--- HashSet与HashMap的关系 ---");
// HashSet内部使用HashMap实现
Set<String> hashSet = new HashSet<>();
// 添加元素到HashSet
hashSet.add("element1");
hashSet.add("element2");
hashSet.add("element3");
System.out.println("HashSet内容: " + hashSet);
// 通过反射查看HashSet的内部实现
try {
Field mapField = HashSet.class.getDeclaredField("map");
mapField.setAccessible(true);
Map<?, ?> internalMap = (Map<?, ?>) mapField.get(hashSet);
System.out.println("HashSet内部使用的Map类型: " + internalMap.getClass().getSimpleName());
System.out.println("内部Map大小: " + internalMap.size());
// 查看内部Map的内容
System.out.println("内部Map键集: " + internalMap.keySet());
} catch (Exception e) {
System.out.println("无法访问内部Map: " + e.getMessage());
}
}
// 自定义对象的HashSet使用
public static void customObjectHashSet() {
System.out.println("\n--- 自定义对象的HashSet使用 ---");
// 不重写hashCode和equals的类
class PersonWithoutOverride {
private String name;
private int age;
public PersonWithoutOverride(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
// 重写hashCode和equals的类
class PersonWithOverride {
private String name;
private int age;
public PersonWithOverride(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;
PersonWithOverride that = (PersonWithOverride) obj;
return age == that.age && Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
// 测试不重写hashCode和equals的情况
Set<PersonWithoutOverride> set1 = new HashSet<>();
PersonWithoutOverride p1 = new PersonWithoutOverride("张三", 25);
PersonWithoutOverride p2 = new PersonWithoutOverride("张三", 25);
set1.add(p1);
set1.add(p2); // 即使内容相同,也会被当作不同对象
System.out.println("不重写hashCode和equals的HashSet:");
System.out.println(" 大小: " + set1.size()); // 输出2
System.out.println(" 内容: " + set1);
// 测试重写hashCode和equals的情况
Set<PersonWithOverride> set2 = new HashSet<>();
PersonWithOverride p3 = new PersonWithOverride("李四", 30);
PersonWithOverride p4 = new PersonWithOverride("李四", 30);
set2.add(p3);
set2.add(p4); // 内容相同,会被当作同一对象
System.out.println("重写hashCode和equals的HashSet:");
System.out.println(" 大小: " + set2.size()); // 输出1
System.out.println(" 内容: " + set2);
}
// LinkedHashSet演示
public static void linkedHashSetDemo() {
System.out.println("\n--- LinkedHashSet演示 ---");
// HashSet不保证顺序
Set<String> hashSet = new HashSet<>();
hashSet.add("C");
hashSet.add("A");
hashSet.add("B");
hashSet.add("D");
System.out.println("HashSet顺序: " + hashSet);
// LinkedHashSet保持插入顺序
Set<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("C");
linkedHashSet.add("A");
linkedHashSet.add("B");
linkedHashSet.add("D");
System.out.println("LinkedHashSet顺序: " + linkedHashSet);
// TreeSet保持排序顺序
Set<String> treeSet = new TreeSet<>();
treeSet.add("C");
treeSet.add("A");
treeSet.add("B");
treeSet.add("D");
System.out.println("TreeSet顺序: " + treeSet);
}
}通过本章节的学习,您已经掌握了Java异常处理机制的核心概念,包括异常体系结构、try-catch-finally语句的使用、throws与throw关键字的应用,以及HashMap和HashSet的实现原理。这些知识对于编写健壮、高效的Java程序至关重要。