学习时间: 4-5小时
学习目标: 掌握Java异常处理机制和集合框架的使用
📋 详细学习清单
✅ 第一部分:异常处理(Exception Handling)(90分钟)
1. 异常概念与JavaScript对比
JavaScript (你熟悉的错误处理)
javascript
// JavaScript 错误处理
function divide(a, b) {
try {
if (b === 0) {
throw new Error("除数不能为0");
}
return a / b;
} catch (error) {
console.error("发生错误:", error.message);
return null;
} finally {
console.log("计算结束");
}
}
// 使用Promise的错误处理
async function fetchData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
return data;
} catch (error) {
console.error("请求失败:", error);
throw error;
}
}
Java (今天学习的异常处理)
java
// Java 异常处理
public class ExceptionExample {
// 方法声明抛出异常
public static double divide(int a, int b) throws ArithmeticException {
try {
if (b == 0) {
throw new ArithmeticException("除数不能为0");
}
return (double) a / b;
} catch (ArithmeticException e) {
System.err.println("发生算术异常: " + e.getMessage());
throw e; // 重新抛出异常
} finally {
System.out.println("计算方法执行完毕");
}
}
public static void main(String[] args) {
try {
double result1 = divide(10, 2);
System.out.println("10 ÷ 2 = " + result1);
double result2 = divide(10, 0); // 这里会抛出异常
System.out.println("10 ÷ 0 = " + result2);
} catch (ArithmeticException e) {
System.out.println("主方法捕获异常: " + e.getMessage());
}
}
}
2. Java异常体系结构
java
/**
* Java异常层次结构:
*
* Throwable (所有异常的父类)
* ├── Error (系统级错误,不建议捕获)
* │ ├── OutOfMemoryError
* │ └── StackOverflowError
* └── Exception (程序异常,需要处理)
* ├── RuntimeException (运行时异常,unchecked)
* │ ├── NullPointerException
* │ ├── ArrayIndexOutOfBoundsException
* │ ├── IllegalArgumentException
* │ └── ArithmeticException
* └── CheckedException (编译时异常,checked)
* ├── IOException
* ├── ClassNotFoundException
* └── SQLException
*/
public class ExceptionHierarchy {
// 演示不同类型的异常
public static void demonstrateExceptions() {
// 1. NullPointerException (运行时异常)
try {
String str = null;
int length = str.length(); // 会抛出NullPointerException
} catch (NullPointerException e) {
System.out.println("空指针异常: " + e.getMessage());
}
// 2. ArrayIndexOutOfBoundsException (运行时异常)
try {
int[] arr = {1, 2, 3};
int value = arr[5]; // 会抛出数组越界异常
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界异常: " + e.getMessage());
}
// 3. NumberFormatException (运行时异常)
try {
String numStr = "abc123";
int num = Integer.parseInt(numStr); // 会抛出数字格式异常
} catch (NumberFormatException e) {
System.out.println("数字格式异常: " + e.getMessage());
}
// 4. 多重catch
try {
String[] array = {"10", "20", null, "abc"};
for (String s : array) {
int num = Integer.parseInt(s);
System.out.println("转换结果: " + num);
}
} catch (NullPointerException e) {
System.out.println("遇到空值: " + e.getMessage());
} catch (NumberFormatException e) {
System.out.println("数字转换失败: " + e.getMessage());
} catch (Exception e) {
System.out.println("其他异常: " + e.getMessage());
}
}
}
3. 自定义异常类
java
// 自定义异常类
class CustomBusinessException extends Exception {
private int errorCode;
public CustomBusinessException(String message) {
super(message);
}
public CustomBusinessException(String message, int errorCode) {
super(message);
this.errorCode = errorCode;
}
public CustomBusinessException(String message, Throwable cause) {
super(message, cause);
}
public int getErrorCode() {
return errorCode;
}
}
// 银行账户示例
class BankAccount {
private String accountId;
private double balance;
public BankAccount(String accountId, double initialBalance) {
this.accountId = accountId;
this.balance = initialBalance;
}
// 取款方法,演示抛出自定义异常
public void withdraw(double amount) throws CustomBusinessException {
if (amount <= 0) {
throw new CustomBusinessException("取款金额必须大于0", 1001);
}
if (amount > balance) {
throw new CustomBusinessException(
String.format("余额不足,当前余额: %.2f, 取款金额: %.2f", balance, amount),
1002
);
}
balance -= amount;
System.out.printf("取款成功,取款金额: %.2f, 剩余余额: %.2f%n", amount, balance);
}
public double getBalance() {
return balance;
}
}
// 使用自定义异常
public class CustomExceptionDemo {
public static void main(String[] args) {
BankAccount account = new BankAccount("ACC001", 1000.0);
try {
account.withdraw(500.0); // 正常取款
account.withdraw(-100.0); // 无效金额
} catch (CustomBusinessException e) {
System.err.println("业务异常 [错误码: " + e.getErrorCode() + "] " + e.getMessage());
}
try {
account.withdraw(800.0); // 余额不足
} catch (CustomBusinessException e) {
System.err.println("业务异常 [错误码: " + e.getErrorCode() + "] " + e.getMessage());
}
}
}
✅ 第二部分:集合框架(Collections Framework)(90分钟)
1. 集合框架概述与JavaScript数组对比
JavaScript (你熟悉的数组和对象)
javascript
// JavaScript 数组和对象操作
let fruits = ["apple", "banana", "orange"];
fruits.push("grape"); // 添加元素
fruits.splice(1, 1); // 删除元素
let hasBanana = fruits.includes("banana"); // 查找元素
let userMap = {
"user1": "张三",
"user2": "李四",
"user3": "王五"
};
userMap["user4"] = "赵六"; // 添加键值对
delete userMap["user2"]; // 删除键值对
// Set数据结构
let uniqueNumbers = new Set([1, 2, 3, 2, 1]);
uniqueNumbers.add(4);
console.log(uniqueNumbers); // Set {1, 2, 3, 4}
Java (今天学习的集合框架)
java
import java.util.*;
public class CollectionsDemo {
public static void demonstrateList() {
System.out.println("=== List 集合演示 ===");
// ArrayList - 动态数组,类似JS Array
List<String> fruits = new ArrayList<>();
fruits.add("apple");
fruits.add("banana");
fruits.add("orange");
fruits.add("banana"); // 允许重复元素
System.out.println("初始水果列表: " + fruits);
// 添加元素
fruits.add(1, "grape"); // 在指定位置插入
System.out.println("插入葡萄后: " + fruits);
// 删除元素
fruits.remove("banana"); // 删除第一个匹配的元素
fruits.remove(2); // 按索引删除
System.out.println("删除操作后: " + fruits);
// 查找和检查
boolean hasApple = fruits.contains("apple");
int grapeIndex = fruits.indexOf("grape");
System.out.println("包含苹果: " + hasApple + ", 葡萄索引: " + grapeIndex);
// 遍历方式
System.out.println("遍历方式1 - 传统for循环:");
for (int i = 0; i < fruits.size(); i++) {
System.out.println(" " + i + ": " + fruits.get(i));
}
System.out.println("遍历方式2 - 增强for循环:");
for (String fruit : fruits) {
System.out.println(" " + fruit);
}
System.out.println("遍历方式3 - Iterator:");
Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
System.out.println(" " + iterator.next());
}
// LinkedList vs ArrayList 性能对比示例
List<Integer> arrayList = new ArrayList<>();
List<Integer> linkedList = new LinkedList<>();
// ArrayList: 随机访问快,中间插入慢
// LinkedList: 顺序访问,中间插入快,随机访问慢
}
public static void demonstrateSet() {
System.out.println("\n=== Set 集合演示 ===");
// HashSet - 无序,不重复
Set<String> hashSet = new HashSet<>();
hashSet.add("Java");
hashSet.add("Python");
hashSet.add("JavaScript");
hashSet.add("Java"); // 重复元素,不会被添加
System.out.println("HashSet (无序): " + hashSet);
// LinkedHashSet - 保持插入顺序,不重复
Set<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("Java");
linkedHashSet.add("Python");
linkedHashSet.add("JavaScript");
linkedHashSet.add("Java");
System.out.println("LinkedHashSet (保持顺序): " + linkedHashSet);
// TreeSet - 自动排序,不重复
Set<String> treeSet = new TreeSet<>();
treeSet.add("Java");
treeSet.add("Python");
treeSet.add("JavaScript");
treeSet.add("C++");
System.out.println("TreeSet (自动排序): " + treeSet);
// Set 操作
Set<Integer> set1 = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5));
Set<Integer> set2 = new HashSet<>(Arrays.asList(4, 5, 6, 7, 8));
// 交集
Set<Integer> intersection = new HashSet<>(set1);
intersection.retainAll(set2);
System.out.println("交集: " + intersection);
// 并集
Set<Integer> union = new HashSet<>(set1);
union.addAll(set2);
System.out.println("并集: " + union);
// 差集
Set<Integer> difference = new HashSet<>(set1);
difference.removeAll(set2);
System.out.println("差集 (set1 - set2): " + difference);
}
public static void demonstrateMap() {
System.out.println("\n=== Map 集合演示 ===");
// HashMap - 键值对,无序
Map<String, String> userMap = new HashMap<>();
userMap.put("user1", "张三");
userMap.put("user2", "李四");
userMap.put("user3", "王五");
userMap.put("user1", "张三三"); // 相同key会覆盖value
System.out.println("HashMap: " + userMap);
// Map 基本操作
String user1Name = userMap.get("user1");
boolean hasUser2 = userMap.containsKey("user2");
boolean hasZhangSan = userMap.containsValue("张三");
System.out.println("user1姓名: " + user1Name);
System.out.println("是否有user2: " + hasUser2);
System.out.println("是否有张三: " + hasZhangSan);
// 遍历Map的几种方式
System.out.println("遍历方式1 - keySet:");
for (String key : userMap.keySet()) {
System.out.println(" " + key + " -> " + userMap.get(key));
}
System.out.println("遍历方式2 - entrySet:");
for (Map.Entry<String, String> entry : userMap.entrySet()) {
System.out.println(" " + entry.getKey() + " -> " + entry.getValue());
}
System.out.println("遍历方式3 - values:");
for (String value : userMap.values()) {
System.out.println(" " + value);
}
// LinkedHashMap - 保持插入顺序
Map<String, Integer> ageMap = new LinkedHashMap<>();
ageMap.put("张三", 25);
ageMap.put("李四", 30);
ageMap.put("王五", 28);
System.out.println("LinkedHashMap (保持顺序): " + ageMap);
// TreeMap - 按键自动排序
Map<String, Integer> sortedAgeMap = new TreeMap<>();
sortedAgeMap.put("张三", 25);
sortedAgeMap.put("李四", 30);
sortedAgeMap.put("王五", 28);
sortedAgeMap.put("赵六", 22);
System.out.println("TreeMap (按键排序): " + sortedAgeMap);
}
public static void main(String[] args) {
demonstrateList();
demonstrateSet();
demonstrateMap();
}
}
2. 集合框架性能对比与选择指南
java
import java.util.*;
public class CollectionPerformanceGuide {
public static void performanceComparison() {
System.out.println("=== 集合性能对比与选择指南 ===");
int dataSize = 100000;
// List性能对比
System.out.println("\n--- List 性能对比 ---");
// ArrayList: 基于数组实现
List<Integer> arrayList = new ArrayList<>();
long startTime = System.currentTimeMillis();
for (int i = 0; i < dataSize; i++) {
arrayList.add(i);
}
long arrayListAddTime = System.currentTimeMillis() - startTime;
// LinkedList: 基于双向链表实现
List<Integer> linkedList = new LinkedList<>();
startTime = System.currentTimeMillis();
for (int i = 0; i < dataSize; i++) {
linkedList.add(i);
}
long linkedListAddTime = System.currentTimeMillis() - startTime;
System.out.println("ArrayList 添加" + dataSize + "个元素耗时: " + arrayListAddTime + "ms");
System.out.println("LinkedList 添加" + dataSize + "个元素耗时: " + linkedListAddTime + "ms");
// 随机访问性能对比
Random random = new Random();
int accessCount = 10000;
startTime = System.currentTimeMillis();
for (int i = 0; i < accessCount; i++) {
int index = random.nextInt(arrayList.size());
arrayList.get(index);
}
long arrayListAccessTime = System.currentTimeMillis() - startTime;
startTime = System.currentTimeMillis();
for (int i = 0; i < accessCount; i++) {
int index = random.nextInt(linkedList.size());
linkedList.get(index);
}
long linkedListAccessTime = System.currentTimeMillis() - startTime;
System.out.println("ArrayList 随机访问" + accessCount + "次耗时: " + arrayListAccessTime + "ms");
System.out.println("LinkedList 随机访问" + accessCount + "次耗时: " + linkedListAccessTime + "ms");
}
/**
* 集合选择指南
*/
public static void selectionGuide() {
System.out.println("\n=== 集合选择指南 ===");
System.out.println("List 选择:");
System.out.println(" ArrayList: 适合频繁随机访问,较少插入删除");
System.out.println(" LinkedList: 适合频繁插入删除,较少随机访问");
System.out.println(" Vector: 线程安全的ArrayList,性能较低");
System.out.println("\nSet 选择:");
System.out.println(" HashSet: 最快的查找性能,无序");
System.out.println(" LinkedHashSet: 保持插入顺序,查找性能略低于HashSet");
System.out.println(" TreeSet: 自动排序,查找性能O(log n)");
System.out.println("\nMap 选择:");
System.out.println(" HashMap: 最快的查找性能,无序");
System.out.println(" LinkedHashMap: 保持插入顺序,查找性能略低于HashMap");
System.out.println(" TreeMap: 按键自动排序,查找性能O(log n)");
System.out.println(" ConcurrentHashMap: 线程安全的HashMap");
}
public static void main(String[] args) {
performanceComparison();
selectionGuide();
}
}
✅ 第三部分:实战练习 (60分钟)
1. 学生管理系统综合练习
java
import java.util.*;
// 学生实体类
class Student {
private String id;
private String name;
private int age;
private double score;
public Student(String id, String name, int age, double score) {
this.id = id;
this.name = name;
this.age = age;
this.score = score;
}
// getter和setter方法
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public double getScore() { return score; }
public void setScore(double score) { this.score = score; }
@Override
public String toString() {
return String.format("Student{id='%s', name='%s', age=%d, score=%.1f}",
id, name, age, score);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Student student = (Student) obj;
return Objects.equals(id, student.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
// 自定义业务异常
class StudentManagementException extends Exception {
public StudentManagementException(String message) {
super(message);
}
}
// 学生管理系统
public class StudentManagementSystem {
private Map<String, Student> students; // 用于快速查找
private List<Student> studentList; // 用于排序和遍历
private Set<String> usedIds; // 用于ID唯一性检查
public StudentManagementSystem() {
this.students = new HashMap<>();
this.studentList = new ArrayList<>();
this.usedIds = new HashSet<>();
}
// 添加学生
public void addStudent(Student student) throws StudentManagementException {
if (student == null) {
throw new StudentManagementException("学生对象不能为空");
}
if (usedIds.contains(student.getId())) {
throw new StudentManagementException("学生ID已存在: " + student.getId());
}
if (student.getScore() < 0 || student.getScore() > 100) {
throw new StudentManagementException("成绩必须在0-100之间");
}
students.put(student.getId(), student);
studentList.add(student);
usedIds.add(student.getId());
System.out.println("添加学生成功: " + student);
}
// 删除学生
public boolean deleteStudent(String id) throws StudentManagementException {
if (id == null || id.trim().isEmpty()) {
throw new StudentManagementException("学生ID不能为空");
}
Student student = students.remove(id);
if (student == null) {
throw new StudentManagementException("未找到ID为 " + id + " 的学生");
}
studentList.remove(student);
usedIds.remove(id);
System.out.println("删除学生成功: " + student);
return true;
}
// 查找学生
public Student findStudent(String id) throws StudentManagementException {
if (id == null || id.trim().isEmpty()) {
throw new StudentManagementException("学生ID不能为空");
}
Student student = students.get(id);
if (student == null) {
throw new StudentManagementException("未找到ID为 " + id + " 的学生");
}
return student;
}
// 更新学生信息
public void updateStudent(String id, String name, int age, double score)
throws StudentManagementException {
Student student = findStudent(id); // 复用查找方法,会抛出相应异常
if (score < 0 || score > 100) {
throw new StudentManagementException("成绩必须在0-100之间");
}
student.setName(name);
student.setAge(age);
student.setScore(score);
System.out.println("更新学生信息成功: " + student);
}
// 按成绩排序
public List<Student> getStudentsSortedByScore() {
List<Student> sortedList = new ArrayList<>(studentList);
sortedList.sort((s1, s2) -> Double.compare(s2.getScore(), s1.getScore())); // 降序
return sortedList;
}
// 统计信息
public void printStatistics() {
if (studentList.isEmpty()) {
System.out.println("暂无学生数据");
return;
}
double totalScore = 0;
double maxScore = Double.MIN_VALUE;
double minScore = Double.MAX_VALUE;
Student topStudent = null;
Student bottomStudent = null;
for (Student student : studentList) {
double score = student.getScore();
totalScore += score;
if (score > maxScore) {
maxScore = score;
topStudent = student;
}
if (score < minScore) {
minScore = score;
bottomStudent = student;
}
}
double averageScore = totalScore / studentList.size();
System.out.println("\n=== 学生统计信息 ===");
System.out.printf("学生总数: %d%n", studentList.size());
System.out.printf("平均分: %.2f%n", averageScore);
System.out.printf("最高分: %.1f (%s)%n", maxScore, topStudent.getName());
System.out.printf("最低分: %.1f (%s)%n", minScore, bottomStudent.getName());
}
// 显示所有学生
public void displayAllStudents() {
if (studentList.isEmpty()) {
System.out.println("暂无学生数据");
return;
}
System.out.println("\n=== 所有学生信息 ===");
for (Student student : studentList) {
System.out.println(student);
}
}
// 按成绩显示学生排名
public void displayStudentRanking() {
List<Student> rankedStudents = getStudentsSortedByScore();
System.out.println("\n=== 学生成绩排名 ===");
for (int i = 0; i < rankedStudents.size(); i++) {
Student student = rankedStudents.get(i);
System.out.printf("第%d名: %s (%.1f分)%n",
i + 1, student.getName(), student.getScore());
}
}
// 测试方法
public static void main(String[] args) {
StudentManagementSystem sms = new StudentManagementSystem();
try {
// 添加学生
sms.addStudent(new Student("S001", "张三", 20, 85.5));
sms.addStudent(new Student("S002", "李四", 19, 92.0));
sms.addStudent(new Student("S003", "王五", 21, 78.5));
sms.addStudent(new Student("S004", "赵六", 20, 88.0));
sms.addStudent(new Student("S005", "钱七", 22, 95.5));
// 显示所有学生
sms.displayAllStudents();
// 查找学生
Student student = sms.findStudent("S003");
System.out.println("\n查找到学生: " + student);
// 更新学生信息
sms.updateStudent("S003", "王五", 21, 82.0);
// 显示排名
sms.displayStudentRanking();
// 显示统计信息
sms.printStatistics();
// 删除学生
sms.deleteStudent("S002");
// 再次显示排名
System.out.println("\n删除学生后的排名:");
sms.displayStudentRanking();
} catch (StudentManagementException e) {
System.err.println("操作失败: " + e.getMessage());
}
// 测试异常情况
System.out.println("\n=== 异常情况测试 ===");
try {
sms.addStudent(new Student("S001", "重复ID", 20, 90)); // ID重复
} catch (StudentManagementException e) {
System.err.println("预期异常: " + e.getMessage());
}
try {
sms.findStudent("S999"); // 不存在的ID
} catch (StudentManagementException e) {
System.err.println("预期异常: " + e.getMessage());
}
try {
sms.addStudent(new Student("S999", "无效成绩", 20, 120)); // 无效成绩
} catch (StudentManagementException e) {
System.err.println("预期异常: " + e.getMessage());
}
}
}
📚 今日学习总结
✅ 掌握的知识点
- 异常处理机制:try-catch-finally、异常层次结构、自定义异常
- 集合框架核心:List、Set、Map的使用和选择
- 性能优化意识:不同集合类型的性能特点
- 综合应用能力:异常处理与集合框架的结合使用
🎯 明日预告
第5天将学习:
- 泛型(Generics)深入理解
- 文件I/O操作
- 序列化与反序列化
- 实战:配置文件读写系统
💡 练习建议
- 运行并修改今天的所有示例代码
- 尝试自己实现一个图书管理系统
- 思考在什么场景下使用哪种集合类型
- 练习自定义异常的设计和使用