Przeglądaj źródła

docs: 更新20260728课堂笔记,同步代码变更——新增finally关键字(资源关闭/三种组合/try-catch-finally)、新增异常常用方法练习题解(ExceptionMethodDemo); 补充练习要点与拓展阅读; 更新README

WanJL 4 godzin temu
rodzic
commit
eb4f2aff3e

+ 2 - 2
README.md

@@ -33,7 +33,7 @@
 | 2026-07-23 | [抽象类 + final + 模板方法 + 代码块 + 接口(含JDK8+新特性):抽象类定义与特点、final 类/方法/变量、模板方法模式、三种代码块、接口定义与实现(Usb→LogiMouse/ROGMouse)、接口 vs 抽象类对比、JDK8默认方法static方法、JDK9私有方法](./课堂笔记/01-JavaSE基础-笔记/20260723-笔记.md) |
 | 2026-07-24 | [多态 + 多态中的转型 + 内部类:多态概念与前提、多态成员访问特点、向上转型/向下转型、instanceof类型判断、多态的好处(开闭原则)、抽象类与多态结合(Animal→Dog;Person→Student/Teacher综合案例)、Usb接口多态案例(NoteBook接入鼠标/猫)、内部类概念与使用场景、成员内部类、私有内部类设计原则](./课堂笔记/01-JavaSE基础-笔记/20260724-笔记.md) |
 | 2026-07-27 | [匿名内部类 + Java API 与 String 类 + Math + 日期时间:内部类三大分类、匿名内部类四种使用方式、综合案例(USB/餐具/学生排序/计算器/动物叫声);API概念、String内存模型/不可变性/可变字符串StringBuffer&StringBuilder/文本块TextBlock JDK15+/String常用方法大全;Math数学类常用方法;日期时间类(Date/LocalDate/LocalTime/LocalDateTime/DateTimeFormatter)](./课堂笔记/01-JavaSE基础-笔记/20260727-笔记.md) |
-| 2026-07-28 | [Java 异常处理:异常概念、Throwable 体系结构(Exception vs Error)、编译期异常 vs 运行时异常、JVM 默认处理、try-catch 多 catch 块、异常常用方法(getMessage/fillInStackTrace/getCause)、throws 抛出、鲁棒性;自定义异常(继承 Exception/继承 RuntimeException 区别);throw 手动抛出 vs throws 声明异常;课后作业回顾 — String 分割去重/统计、LocalDate 日期天数差计算](./课堂笔记/01-JavaSE基础-笔记/20260728-笔记.md) |
+| 2026-07-28 | [Java 异常处理:异常概念、Throwable 体系结构、编译期/运行时异常、JVM 默认处理、try-catch 多 catch 块、异常常用方法(getMessage/printStackTrace/getCause/fillInStackTrace)、finally 一定会执行的代码(资源关闭)、throws 抛出、鲁棒性;自定义异常(继承 Exception/继承 RuntimeException);throw 手动抛出 vs throws 声明异常;课后作业回顾 — String 分割去重/统计、LocalDate 天数差计算](./课堂笔记/01-JavaSE基础-笔记/20260728-笔记.md) |
 
 ## 二、授课代码
 
@@ -53,7 +53,7 @@
 | 2026-07-23 | 抽象类 + final + 模板方法 + 代码块 + 接口(含JDK8+新特性):抽象类定义与特点、final 类/方法/变量、模板方法模式(MyOneDayTemplate)、三种代码块(局部/构造/静态)、接口定义与实现(Usb→LogiMouse/ROGMouse)、接口 vs 抽象类对比、JDK8默认方法/静态方法(MyDefaultInterface→MyDefaultInterfaceImpl)、JDK9私有方法(抽取多个默认方法公共代码)、Test05 测试类 | `c260723` | [`course`](./授课代码/c260723/src/course/) |
 | 2026-07-24 | 多态概念与前提、多态成员访问特点、向上转型/向下转型、instanceof运算符、多态的好处(开闭原则)、抽象类+多态(Animal→Dog、Person→Student/Teacher→Test03.runPerson())、接口多态(Usb→Mouse/Cat→NoteBook)、内部类概念与使用场景 | `c260724` | [`course/polymorphism`](./授课代码/c260724/src/course/polymorphism/) / [`course/internalClass`](./授课代码/c260724/src/course/internalClass/) |
 | 2026-07-27 | 匿名内部类:内部类三大分类概念回顾、匿名内部类语法格式与本质、三种使用方式(多态接收变量赋值 / 方法参数传递 / 匿名对象直接调用)、配套接口/抽象类定义(Usb / Tableware / Compute / Sort)、综合案例(NoteBook USB设备 / Person 餐具 / 学生排序比较 / Calculator计算器 / Animal动物叫声);Java API:API概念、String类(内存模型/构造方法/==与equals/常用方法大全/不可变性)、可变字符串(StringBuffer/SringBuilder)、文本块TextBlock JDK15+;Math数学类;日期时间类(Date/LocalDate/LocalTime/LocalDateTime/DateTimeFormatter) | `c260727` | [`course/anonymousInternalClass`](./授课代码/c260727/src/course/anonymousInternalClass/) / [`course/api`](./授课代码/c260727/src/course/api/) / [`course/api/string`](./授课代码/c260727/src/course/api/string/) / [`course/api/math`](./授课代码/c260727/src/course/api/math/) / [`course/api/date`](./授课代码/c260727/src/course/api/date/) / [`exercise/exercise01`](./授课代码/c260727/src/exercise/exercise01/) / [`exercise/exercise06`](./授课代码/c260727/src/exercise/exercise06/) / [`exercise/exercise07`](./授课代码/c260727/src/exercise/exercise07/) / [`homework_0724/p2_myarray`](./授课代码/c260727/src/homework_0724/p2_myarray/) |
-| 2026-07-28 | Java 异常处理(Demo01异常常用方法 + Demo02自定义异常 + Demo03 throw/throws + Person+AgeOutOfBoundsException) + 课后作业回顾(String工具 + 日期数学计算) | `c260728` | [`course`](./授课代码/c260728/src/course/) / [`homework260727`](./授课代码/c260728/src/homework260727/) |
+| 2026-07-28 | Java 异常处理(Demo01异常常用方法 + Demo02自定义异常 + Demo03 throw/throws + Demo04 finally + Person+AgeOutOfBoundsException) + 课后作业回顾(String工具 + 日期数学计算) + Exercise07异常常用方法综合 | `c260728` | [`course`](./授课代码/c260728/src/course/) / [`homework260727`](./授课代码/c260728/src/homework260727/) / [`exercise/exercise07`](./授课代码/c260728/src/exercise/exercise07/) |
 
 ## 三、课堂练习题
 

+ 74 - 0
授课代码/c260728/src/course/Demo04.java

@@ -0,0 +1,74 @@
+package course;
+
+import java.util.Scanner;
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title Demo04
+ * @description finally
+ * @create 2026/7/28
+ */
+public class Demo04 {
+    /*
+        我们上午说了
+        怎么自定义异常?
+            创建异常类
+            继承Exception或RuntimeException
+            创建无参和有参构造方法
+        怎么声明异常类型?
+            使用 throws 在方法声明的后面,表示在调用这个方法的时候可能触发该异常。
+        怎么抛出异常?
+            使用 throw 在方法体里面,一般是在流程控制语句中使用,表示满足某个条件后,抛出该异常对象。
+        怎么捕获处理异常?
+            使用try{}catch(异常类型 变量名){异常信息}  来扫描可能出现异常的代码,设置要捕获的异常类型,以及处理方式。
+
+        我们发现,无论是自己处理异常,还是抛出异常,异常代码后面的代码一般都不会继续执行了。
+        但是有些代码是必须要执行的。比如关闭资源、关闭线程等等...
+        比如使用Scanner
+     */
+    public static void main(String[] args) {
+        Scanner sc=new Scanner(System.in);
+        System.out.println("请输入:");
+        String s = sc.next();
+        System.out.println("您输出的是:"+s);
+
+        try{
+            int i=10/0;
+        }catch (Exception e){
+            System.out.println(e.getMessage());
+        }finally {
+            //这种关闭资源的代码是必须要被执行的,这时候就可以使用finally
+            //这里面的代码一定会被执行
+            sc.close();
+            System.out.println("关闭资源....");
+        }
+
+        /*
+            捕获处理异常的操作:有这样几种组合:
+            最完整的:
+                try{
+                    可能出现异常的代码
+                }catch(异常类型 变量名){
+                    异常处理代码
+                }finally{
+                    一定会被执行的代码
+                }
+             基本的捕获和处理:
+                try{
+                    可能出现异常的代码
+                }catch(异常类型 变量名){
+                    异常处理代码
+                }
+             扫描但不处理:
+                try{
+                    可能出现异常的代码
+                }finally{
+                    一定会被执行的代码
+                }
+         */
+
+
+
+    }
+}

+ 108 - 0
授课代码/c260728/src/exercise/exercise07/ExceptionMethodDemo.java

@@ -0,0 +1,108 @@
+package exercise.exercise07;
+
+import java.io.FileNotFoundException;
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title ExceptionMethodDemo
+ * @description
+ * @create 2026/7/28
+ */
+public class ExceptionMethodDemo {
+
+    /**
+     * 任务 1:体验 getMessage() 和 printStackTrace()
+     * 传入一个数组和索引,尝试访问该索引的元素
+     */
+    public static void accessArray(int[] arr, int index) {
+        try {
+            System.out.println("数组元素:" + arr[index]);
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // 1. 输出异常的描述信息(getMessage())
+            System.out.println("getMessage() 输出:" + e.getMessage());
+
+            // 2. 输出异常的完整堆栈信息(printStackTrace())
+            System.out.println("printStackTrace() 输出(请补充调用):");
+            // 请在下面调用 e.printStackTrace();
+            e.printStackTrace();
+            // 3. 输出异常的类名
+            System.out.println("异常类名:" + e.getClass().getName());
+
+            // 4. 输出异常的原因(getCause())
+            System.out.println("getCause() 输出:" + e.getCause());
+        }
+    }
+
+    /**
+     * 任务 2:体验 fillInStackTrace()
+     * 模拟多层方法调用中的异常传递
+     */
+    public static void methodA() throws Exception {
+        methodB();  // 调用 methodB,methodB 会抛出异常
+    }
+
+    public static void methodB() throws Exception {
+        // 请在此处手动抛出一个 Exception,描述信息为 "methodB 中发生异常"
+        // 使用 throw new Exception("...")
+        throw new Exception("methodB 中发生异常");
+    }
+
+    public static void testFillInStackTrace() {
+        try {
+            methodA();
+        } catch (Exception e) {
+            System.out.println("原始异常信息:" + e.getMessage());
+            System.out.println("原始堆栈(调用 printStackTrace):");
+            e.printStackTrace();  // 显示原始异常发生位置
+
+            System.out.println("\n--- 以下为 fillInStackTrace 后的异常 ---");
+            // 调用 fillInStackTrace() 会重置堆栈信息到当前行
+            // 使得异常看起来像是在当前方法抛出的
+            //Throwable newException = e.fillInStackTrace();
+            //newException.printStackTrace();
+        }
+    }
+
+    /**
+     * 任务 3:模拟异常链(getCause)
+     * 将底层异常包装为高层异常,保留 cause 信息
+     */
+    public static void readFile(String path) throws Exception {
+        try {
+            // 模拟一个底层异常:文件未找到
+            throw new FileNotFoundException("文件 " + path + " 不存在!");
+        } catch (FileNotFoundException e) {
+            // 将底层异常包装为高层异常,并保留 cause
+            throw new Exception("读取文件失败,路径:" + path, e);
+        }
+    }
+
+    public static void testExceptionChain() {
+        try {
+            readFile("/data/config.txt");
+        } catch (Exception e) {
+            System.out.println("===== 异常链测试 =====");
+            System.out.println("高层异常信息:" + e.getMessage());
+            System.out.println("高层异常类名:" + e.getClass().getName());
+
+            // 获取底层异常(cause)
+            Throwable cause = e.getCause();
+            System.out.println("\n底层异常(cause):" + cause);
+            System.out.println("底层异常信息:" + cause.getMessage());
+            System.out.println("底层异常类名:" + cause.getClass().getName());
+        }
+    }
+
+    public static void main(String[] args) {
+        System.out.println("========== 任务 1:getMessage 与 printStackTrace ==========");
+        int[] arr = {1, 2, 3};
+        accessArray(arr, 5);
+
+        System.out.println("\n========== 任务 2:fillInStackTrace ==========");
+        testFillInStackTrace();
+
+        System.out.println("\n========== 任务 3:异常链 getCause ==========");
+        testExceptionChain();
+    }
+}

+ 49 - 2
课堂笔记/01-JavaSE基础-笔记/20260728-笔记.md

@@ -163,6 +163,51 @@ public void method() throws IOException {
 
 > 📄 来源:`Demo01.java`
 
+### 1.8 finally — 一定会被执行的代码
+
+#### 为什么需要 finally
+
+无论是自己处理异常(try-catch),还是抛出异常(throw),**异常代码后面的代码一般都不会继续执行了**。但有些代码是**必须执行**的,比如:
+- 关闭资源(`Scanner`、文件流、数据库连接等)
+- 关闭线程
+- 释放锁
+
+`finally` 块就可以保证这些代码**无论是否发生异常,都一定会被执行**。
+
+#### 语法格式 — 三种组合
+
+| 组合 | 格式 | 说明 |
+|------|------|------|
+| **最完整** | `try { ... } catch (E e) { ... } finally { ... }` | 捕获异常 + 释放资源 |
+| **基本** | `try { ... } catch (E e) { ... }` | 仅捕获处理异常 |
+| **扫描但不处理** | `try { ... } finally { ... }` | 不捕获异常,但确保资源关闭(异常会继续向上抛) |
+
+#### 代码示例
+
+```java
+Scanner sc = new Scanner(System.in);
+System.out.println("请输入:");
+String s = sc.next();
+System.out.println("您输出的是:" + s);
+
+try {
+    int i = 10 / 0;        // 会抛出 ArithmeticException
+} catch (Exception e) {
+    System.out.println(e.getMessage());   // 捕获并处理
+} finally {
+    // finally 块中的代码一定会被执行
+    sc.close();                           // 关闭 Scanner 资源
+    System.out.println("关闭资源....");
+}
+```
+
+> 📄 来源:`Demo04.java`
+
+**关键特点:**
+- `finally` 块中的代码**无论 try 块是否发生异常,都一定会执行**
+- 即使 catch 块中有 `return` 语句,`finally` 块也会在 `return` 之前执行
+- `finally` 块通常用于**资源清理**,如关闭 `Scanner`、关闭文件流等
+
 ---
 
 ## 二、自定义异常(Custom Exception)
@@ -456,8 +501,10 @@ System.out.println("距离 2026-12-31 还有:" + (epochDay - now) + "天");
 - 理解 `Throwable` → `Exception` → `RuntimeException` 的继承体系
 - 区分编译期异常和运行时异常
 - 掌握 `try-catch` 多 catch 块的写法,注意异常类型顺序(子类→父类)
+- 掌握 `finally` 块的使用:`try-catch-finally`(完整)、`try-finally`(扫描但不处理)
+- 理解 `finally` 块一定会被执行的特性,常用于关闭资源(如 `Scanner.close()`)
 - 理解 `JVM` 默认处理异常的方式(打印信息 + 终止程序)
-- 熟悉异常常用方法:`getMessage()`、`fillInStackTrace()`、`getCause()`
+- 熟悉异常常用方法:`getMessage()`、`fillInStackTrace()`、`getCause()`、`printStackTrace()`
 - 掌握 `throw` 手动抛出异常对象(在方法体内部使用)
 - 掌握 `throws` 声明异常(在方法签名上使用),理解两者的区别
 - 掌握自定义异常的创建步骤(继承 Exception → 无参/有参构造方法)
@@ -482,7 +529,7 @@ System.out.println("距离 2026-12-31 还有:" + (epochDay - now) + "天");
 ## 七、拓展阅读
 
 1. **Java 异常处理最佳实践** — 何时使用 checked vs unchecked exception,何时自定义异常
-2. **try-with-resources** — JDK7+ 自动关闭资源的异常处理方式(`try(Resource r = new Resource()){...}`)
+2. **try-with-resources** — JDK7+ 自动关闭资源的异常处理方式(`try(Resource r = new Resource()){...}`),是 `finally` 关闭资源方式的进化版,无需手动写 `finally` 块
 3. **异常链(Exception Chaining)** — 通过 `initCause()` 或构造方法将底层异常包装为高层异常
 4. **`Objects.requireNonNull()`** — 一种优雅避免 NullPointerException 的方式(JDK7+)
 5. **`Period` 与 `Duration`** — Java 8 日期时间 API 中更灵活的时间间隔计算