|
|
@@ -0,0 +1,292 @@
|
|
|
+# JavaSE 基础 — Day12 笔记
|
|
|
+
|
|
|
+> **日期**:2026-07-28
|
|
|
+> **项目**:`c260728`
|
|
|
+> **作者**:WanJL
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 一、Java 异常处理(Exception Handling)
|
|
|
+
|
|
|
+### 1.1 异常的概念
|
|
|
+
|
|
|
+**异常(Exception)** 就是程序出现不正常的情况。
|
|
|
+
|
|
|
+在 Java 中,异常和错误都继承自 `Throwable` 类:
|
|
|
+
|
|
|
+```
|
|
|
+Throwable(顶级父类)
|
|
|
+ ├── Exception(异常类 — 程序本身可以处理的问题)
|
|
|
+ │ ├── RuntimeException(运行时异常)
|
|
|
+ │ │ ├── ArithmeticException(算术异常,如除零)
|
|
|
+ │ │ ├── ArrayIndexOutOfBoundsException(数组下标越界)
|
|
|
+ │ │ ├── NullPointerException(空指针异常)
|
|
|
+ │ │ └── ...
|
|
|
+ │ └── 非 RuntimeException(编译期异常 — 编译时必须处理)
|
|
|
+ │ ├── IOException
|
|
|
+ │ ├── SQLException
|
|
|
+ │ └── ...
|
|
|
+ └── Error(错误类 — 严重问题,代码无法处理)
|
|
|
+ ├── StackOverflowError(栈溢出,如无限制递归)
|
|
|
+ ├── OutOfMemoryError(内存溢出)
|
|
|
+ └── ...
|
|
|
+```
|
|
|
+
|
|
|
+> 📄 来源:`Demo01.java`
|
|
|
+
|
|
|
+**核心要点:**
|
|
|
+- **`Exception`** 及其子类可以被我们捕获处理或抛出,是程序可以处理的问题。
|
|
|
+- **`Error`** 是内存级别的严重问题,不是我们可以捕获抛出的,需要改代码。
|
|
|
+- 只有 `Exception` 类或其子类,才可以被我们捕获处理或抛出。
|
|
|
+
|
|
|
+### 1.2 编译期异常 vs 运行时异常
|
|
|
+
|
|
|
+| 类型 | 说明 | 示例 |
|
|
|
+|------|------|------|
|
|
|
+| **编译期异常**(Checked Exception) | 编译时就会报错,必须处理(捕获/抛出)才能通过编译 | `IOException`, `SQLException` |
|
|
|
+| **运行时异常**(Runtime Exception) | 编译时不报错,运行后才报错。所有运行时异常的父类是 `RuntimeException` | `ArithmeticException`, `NullPointerException`, `ArrayIndexOutOfBoundsException` |
|
|
|
+
|
|
|
+**Java 程序执行流程:**
|
|
|
+
|
|
|
+```text
|
|
|
+.java(源代码) ---[javac 编译]---> .class(字节码) ---[java 解释]---> 运行结果
|
|
|
+ 编译期 运行期
|
|
|
+```
|
|
|
+
|
|
|
+- **编译期异常**:在 Java 源代码编译成字节码的过程中出现,必须处理。
|
|
|
+- **运行期异常**:编译阶段没有任何错误,但在从字节码文件解释运行获取结果期间出现错误。
|
|
|
+
|
|
|
+> 📄 来源:`Demo01.java`
|
|
|
+
|
|
|
+### 1.3 JVM 对异常的默认处理
|
|
|
+
|
|
|
+如果程序出了问题,我们不做任何处理,最终会由 **JVM 做默认处理**,处理步骤:
|
|
|
+
|
|
|
+1. 把 **异常的名称、错误原因、以及异常出现的位置** 等信息输出在控制台
|
|
|
+2. **程序停止运行**
|
|
|
+
|
|
|
+> 📄 来源:`Demo01.java`
|
|
|
+
|
|
|
+### 1.4 异常处理方式一:try-catch 捕获处理
|
|
|
+
|
|
|
+#### 语法格式
|
|
|
+
|
|
|
+```java
|
|
|
+try {
|
|
|
+ // 可能出现异常的代码
|
|
|
+} catch (异常类型1 变量名) {
|
|
|
+ // 异常类型1的处理方式
|
|
|
+} catch (异常类型2 变量名) {
|
|
|
+ // 异常类型2的处理方式
|
|
|
+} catch (异常类型n 变量名) {
|
|
|
+ // 异常类型n的处理方式
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### 多个 catch 块的执行顺序
|
|
|
+
|
|
|
+- 多个 `catch` 块遵循 **从上到下匹配** 的原则
|
|
|
+- 一旦匹配到某个异常类型,就执行对应的 catch 块,然后跳出 try-catch 结构
|
|
|
+- 建议将 **子类异常放在前面,父类异常放在后面**,否则父类异常会"拦住"子类异常,导致子类 catch 块不可达
|
|
|
+
|
|
|
+#### 代码示例
|
|
|
+
|
|
|
+```java
|
|
|
+int a = 0;
|
|
|
+try {
|
|
|
+ int[] arr = {};
|
|
|
+ arr[3] = 5; // 数组下标越界 → ArrayIndexOutOfBoundsException
|
|
|
+} catch (ArithmeticException e) {
|
|
|
+ System.out.println("不能除以0");
|
|
|
+ System.out.println("以及一些其他的异常处理操作.....");
|
|
|
+} catch (RuntimeException e) {
|
|
|
+ System.out.println("出现了运行时异常");
|
|
|
+} catch (Exception e) {
|
|
|
+ System.out.println("出现了异常..但不是运行时异常");
|
|
|
+}
|
|
|
+System.out.println(a);
|
|
|
+System.out.println("........后续的代码正在运行................");
|
|
|
+```
|
|
|
+
|
|
|
+> 📄 来源:`Demo01.java`
|
|
|
+
|
|
|
+**输出结果分析:** 由于 `arr[3] = 5` 抛出的是 `ArrayIndexOutOfBoundsException`,它是 `RuntimeException` 的子类,因此会被第二个 catch 块捕获,输出"出现了运行时异常",然后程序继续执行后续代码。
|
|
|
+
|
|
|
+### 1.5 异常处理方式二:throws 抛出
|
|
|
+
|
|
|
+我们不处理异常,交给调用者去处理。如果方法内包含编译期异常,可以不在方法内处理,只使用 `throws` 抛出:
|
|
|
+- 谁调用了这个方法,谁去处理
|
|
|
+- 调用者如果不处理,可以继续抛出
|
|
|
+- 最终抛给 JVM,JVM 进行默认的处理
|
|
|
+
|
|
|
+```java
|
|
|
+public void method() throws IOException {
|
|
|
+ // 方法体中的编译期异常不处理,交给调用者
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+> 📄 来源:`Demo01.java`(概念说明)
|
|
|
+
|
|
|
+### 1.6 异常处理的编程思想 — 鲁棒性(健壮性)
|
|
|
+
|
|
|
+- **处理异常**:能处理就处理,处理不了的也要让程序能够继续运行,这才是最重要的
|
|
|
+- **鲁棒性(Robustness)**:程序出现异常但能够处理或能够正常运行,体现程序的健壮性
|
|
|
+- 实际开发场景:兜住异常,记录日志,给开发人员发邮件
|
|
|
+
|
|
|
+> 📄 来源:`Demo01.java`
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 二、课后作业回顾 — StringUtilTest 字符串工具测试
|
|
|
+
|
|
|
+### 2.1 需求说明
|
|
|
+
|
|
|
+给定有前后空格和重复项的字符串数据 `" 张三, 李四, 王五, 赵六, 张三, 钱七 "`,需要:
|
|
|
+1. 去除每个元素的前后空格
|
|
|
+2. 去重(去除重复的姓名)
|
|
|
+3. 统计每个姓名的出现次数
|
|
|
+
|
|
|
+### 2.2 相关 API
|
|
|
+
|
|
|
+| 方法 | 说明 |
|
|
|
+|------|------|
|
|
|
+| `String.split(String regex)` | 按指定正则表达式分割字符串为字符串数组 |
|
|
|
+| `String.trim()` | 去除字符串前后的空白字符 |
|
|
|
+| `Arrays.toString(Object[] a)` | 将数组转换为字符串表示形式 |
|
|
|
+
|
|
|
+### 2.3 核心算法
|
|
|
+
|
|
|
+#### 三步去重算法
|
|
|
+
|
|
|
+```java
|
|
|
+String data = " 张三, 李四, 王五, 赵六, 张三, 钱七 ";
|
|
|
+
|
|
|
+// 第一步:分割 + 去空格
|
|
|
+String[] split = data.split(",");
|
|
|
+for (int i = 0; i < split.length; i++) {
|
|
|
+ split[i] = split[i].trim();
|
|
|
+}
|
|
|
+
|
|
|
+// 第二步:统计不重复元素个数
|
|
|
+int count = 0;
|
|
|
+for (int i = 0; i < split.length; i++) {
|
|
|
+ boolean b = false;
|
|
|
+ for (int j = 0; j < i; j++) {
|
|
|
+ if (split[i].equals(split[j])) {
|
|
|
+ b = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (b == false) {
|
|
|
+ count++;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 第三步:创建新数组,放入不重复元素
|
|
|
+String[] newArr = new String[count];
|
|
|
+int index = 0;
|
|
|
+for (int i = 0; i < split.length; i++) {
|
|
|
+ boolean b = false;
|
|
|
+ for (int j = 0; j < i; j++) {
|
|
|
+ if (split[i].equals(split[j])) {
|
|
|
+ b = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (b == false) {
|
|
|
+ newArr[index] = split[i];
|
|
|
+ index++;
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### 统计元素出现次数
|
|
|
+
|
|
|
+```java
|
|
|
+for (int i = 0; i < newArr.length; i++) {
|
|
|
+ int count02 = 0;
|
|
|
+ for (int j = 0; j < split.length; j++) {
|
|
|
+ if (newArr[i].equals(split[j])) {
|
|
|
+ count02++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ System.out.println(newArr[i] + ":" + count02 + "次");
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+> 📄 来源:`StringUtilTest.java`
|
|
|
+
|
|
|
+**关键知识点:**
|
|
|
+- `split[i].equals(split[j])` — 字符串比较使用 `equals()`,不能使用 `==`
|
|
|
+- 双重循环 + 标记位(`boolean b`)实现去重
|
|
|
+- 先统计个数再创建数组,避免数组长度不确定的问题
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 三、课后作业回顾 — DataMathTest 日期时间计算
|
|
|
+
|
|
|
+### 3.1 需求说明
|
|
|
+
|
|
|
+计算当前日期距离 2026-12-31 还有多少天。
|
|
|
+
|
|
|
+### 3.2 相关 API
|
|
|
+
|
|
|
+| 方法 | 说明 |
|
|
|
+|------|------|
|
|
|
+| `LocalDate.of(int year, int month, int dayOfMonth)` | 创建指定日期的 `LocalDate` 对象 |
|
|
|
+| `LocalDate.toEpochDay()` | 返回从 1970-01-01 到当前日期的天数 |
|
|
|
+
|
|
|
+### 3.3 代码实现
|
|
|
+
|
|
|
+```java
|
|
|
+LocalDate localDate = LocalDate.of(2026, 7, 27);
|
|
|
+LocalDate localDate2 = LocalDate.of(2026, 12, 31);
|
|
|
+long now = localDate.toEpochDay(); // 距离 1970-01-01 有多少天
|
|
|
+long epochDay = localDate2.toEpochDay(); // 距离 1970-01-01 有多少天
|
|
|
+System.out.println("距离 2026-12-31 还有:" + (epochDay - now) + "天");
|
|
|
+```
|
|
|
+
|
|
|
+> 📄 来源:`DataMathTest.java`
|
|
|
+
|
|
|
+**输出结果:** `距离 2026-12-31 还有:157 天`
|
|
|
+
|
|
|
+**关键知识点:**
|
|
|
+- `toEpochDay()` 返回的是 `long` 类型,表示从 1970-01-01(Epoch)到当前日期的天数
|
|
|
+- 两个日期的天数相减即可得到间隔天数
|
|
|
+- 也可以使用 `LocalDate.until(ChronoUnit.DAYS)` 或 `Period.between()` 实现
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 四、随堂练习要点
|
|
|
+
|
|
|
+### 4.1 异常处理练习要点
|
|
|
+
|
|
|
+- 理解 `Throwable` → `Exception` → `RuntimeException` 的继承体系
|
|
|
+- 区分编译期异常和运行时异常
|
|
|
+- 掌握 `try-catch` 多 catch 块的写法,注意异常类型顺序(子类→父类)
|
|
|
+- 理解 `JVM` 默认处理异常的方式(打印信息 + 终止程序)
|
|
|
+- 体会异常处理对程序 **鲁棒性(健壮性)** 的提升
|
|
|
+
|
|
|
+### 4.2 字符串处理综合练习要点
|
|
|
+
|
|
|
+- 使用 `split(",")` 分割带分隔符的字符串
|
|
|
+- 使用 `trim()` 去除字符串前后空格
|
|
|
+- 掌握数组去重算法(双重循环 + 标记位)
|
|
|
+- 掌握元素出现次数的统计算法
|
|
|
+- 理解 `equals()` 在字符串比较中的必要性
|
|
|
+
|
|
|
+### 4.3 日期时间计算练习要点
|
|
|
+
|
|
|
+- 使用 `LocalDate.of()` 创建指定日期
|
|
|
+- 使用 `toEpochDay()` 计算两个日期之间的天数差
|
|
|
+- 了解其他可选方案:`until()`、`Period.between()`、`ChronoUnit.DAYS.between()`
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 五、拓展阅读
|
|
|
+
|
|
|
+1. **Java 异常处理最佳实践** — 何时使用 checked vs unchecked exception
|
|
|
+2. **try-with-resources** — JDK7+ 自动关闭资源的异常处理方式
|
|
|
+3. **自定义异常** — 继承 `Exception` 或 `RuntimeException` 创建业务异常
|
|
|
+4. **`Period` 与 `Duration`** — Java 8 日期时间 API 中更灵活的时间间隔计算
|
|
|
+5. **`LinkedHashSet` 去重** — 利用集合类简化去重操作(替代手动数组去重)
|