前言

  • Java进阶课程的第一篇,异常相关内容。

  • 学习完基础之后就是进阶的内容了。


包含的知识

  1. 异常的基础知识
  • 异常的概念:异常是在程序执行过程中发生的、中断程序正常流程的事件。
  • 异常的分类:
    • 运行时异常(RuntimeException及其子类):这类异常通常由编程错误引起,如空指针访问、数组越界等。它们不需要在方法签名中声明,也不强制要求捕获。
    • 编译时异常(非RuntimeException):这类异常通常由外部因素引起,如文件不存在、网络连接失败等。它们必须在方法签名中声明或在方法内部捕获。
  1. 异常处理机制
  • try-catch 结构:用于捕获和处理异常。try块中放置可能抛出异常的代码,catch块中处理捕获到的异常。
  • finally 块:无论是否发生异常,finally块中的代码都会被执行,通常用于资源的释放。
  • throw 关键字:用于手动抛出异常。
  • throws 关键字:用于声明一个方法可能会抛出的异常。
  1. 预定义异常
  • ArrayIndexOutOfBoundsException:数组下标越界异常。
  • ArithmeticException:算术异常,例如除以零。
  • NullPointerException:空指针异常,尝试访问空对象的方法或属性。
  • ParseException:解析异常,通常发生在日期或数字的解析过程中。
  • FileNotFoundException:文件未找到异常,尝试读取不存在的文件时抛出。
  1. 自定义异常
  • 继承Exception:创建自定义的编译时异常。
  • 继承RuntimeException:创建自定义的运行时异常。
  • 构造器:自定义异常类通常需要重写构造器,以便传递异常消息。
  1. 异常处理策略
  • 向上抛出:将异常抛给调用者处理,适用于无法在当前层级解决异常的情况。
  • 捕获并处理:在当前层级捕获异常并尝试解决问题,或者记录错误信息并给出用户友好的反馈。
  • 记录异常:使用e.printStackTrace()或其他日志工具记录异常信息,便于调试和问题追踪。
  1. 具体示例
  • show() 方法:演示了运行时异常的几种常见类型。
  • show1() 方法:演示了编译时异常的处理方式。
  • div(int a, int b) 方法:展示了如何在方法中检查参数合法性并抛出异常。
  • saveAge0(int age) 和 saveAge1(int age) 方法:演示了自定义异常的使用,分别处理编译时异常和运行时异常。
  1. 注意
  • 具体异常类型:尽量使用具体的异常类型,而不是通用的Exception,以便更精确地处理特定的错误情况。

具体代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package ADV_0;

import java.io.FileInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;

public class ADVZc0 {
public static void main(String[] args) {
// 异常的基本作用
show();
try {
// 监视代码,出现异常,会被catch拦截住这个异常
show1();
} catch (Exception e) { // Exception 是所有异常的父类
e.printStackTrace(); // 打印这个异常信息
}

// 异常的作用
System.out.println("==div程序开始执行...==");
try {
System.out.println(div(10, 0));
System.out.println("底层方法执行成功");
} catch (Exception e) {
e.printStackTrace();
System.out.println("底层方法执行失败");
}
System.out.println("==程序结束==");

// 自定义异常
System.out.println("==age0程序开始执行...==");
try {
saveAge0(300);
System.out.println("成功");
} catch (ItheimaAgeIllegalException e) {// 不同点
e.printStackTrace();
System.out.println("失败");
}
System.out.println("==程序结束==");

// 自定义异常-运行时异常
System.out.println("==age1程序开始执行...==");
try {
saveAge0(300);
System.out.println("成功");
} catch (Exception e) { // 不同点
e.printStackTrace();
System.out.println("失败");
}
System.out.println("==程序结束==");

// 异常的处理方案1: 底层异常都抛出去给最外层调用者,最外层捕获异常,记录异常,响应合适信息给用户观看
System.out.println("==程序开始执行show2...==");
try {
show2();
System.out.println("操作成功");
} catch (Exception e) {
e.printStackTrace();
System.out.println("操作失败");
}
System.out.println("==程序结束==");

// 异常的处理方案2:捕获异常对象,尝试重新修复。
// 接收用户的一个定价
System.out.println("==shop程序开始执行...==");
while (true) {
try {
double price = userInputPrice();
System.out.println("用户成功设置了商品定价:" + price);
break;
} catch (Exception e) {
System.out.println("您输入的数据是瞎搞的,请不要瞎输入价格!");
}
}
System.out.println("==程序结束==");
}

// 定义一个方法认识运行时异常
public static void show(){
System.out.println("==程序开始执行show...==");
// 运行异常:运行阶段报错,继承自 RuntimeException
int[] arr = {1,2,3};
// System.out.println(arr[3]); // ArrayIndexOutOfBoundsException

// System.out.println(10/0); // ArithmeticException

// 空指针异常
//String str = null;System.out.println(str);System.out.println(str.length()); // NullPointerException
System.out.println("==程序结束==");
}

public static void show1() throws Exception {
System.out.println("==程序开始执行show1...==");
// 编译异常:编译阶段报错,编译不通过
String str = "2024-11-25 8:30:00";
// 把字符串时间解析成Java中的一个日期对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = sdf.parse(str); // 编译时异常,提醒程序员这里的程序很容易出错,请注意
System.out.println(date);
// 任意输入一个图片路径
InputStream is = new FileInputStream("D:/tupian.png");

System.out.println("==程序结束==");
}

// 两数相除返回结果
public static int div(int a, int b) throws Exception {
if(b == 0){
System.out.println("除数不能为0,您的参数有问题!");
// 可以返回一个异常给上层调用者,返回的异常还能告知上层底层是执行成功了还是执行失败了
throw new Exception("除数不能为0,您的参数有问题!(红)");
}
int result = a / b;
return result;
}

// 年龄小于1岁或者大于200岁是异常
public static void saveAge0(int age) throws ItheimaAgeIllegalException {
if(age < 1 || age > 200){
// 年龄非法;抛出一个异常
throw new ItheimaAgeIllegalException("年龄非法 age 不能低于1岁不能高于200岁");
}else {
System.out.println("年龄合法");
System.out.println("保存年龄:" + age);
}
}

// 年龄小于1岁或者大于200岁是异常
public static void saveAge1(int age) {
if(age < 1 || age > 200){
// 年龄非法;抛出一个异常
throw new ItheimaAgeIllegalRuntimeException("年龄非法 age 不能低于1岁不能高于200岁");
}else {
System.out.println("年龄合法");
System.out.println("保存年龄:" + age);
}
}

public static void show2() throws Exception {
// 编译异常:编译阶段报错,编译不通过。
String str = "2024-07-09 11:12:13";
// 把字符串时间解析成Java中的一个日期对象。
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = sdf.parse(str); // 编译时异常,提醒程序员这里的程序很容易出错,请您注意!
System.out.println(date);

InputStream is = new FileInputStream("D:/tupian.png");
}

public static double userInputPrice(){
Scanner sc = new Scanner(System.in);
System.out.println("请您输入商品定价:");
double price = sc.nextDouble();
return price;
}
}



/**
* 自定义的编译异常
* 1、继承Exception
* 2、重写Exception的构造器。
* 3、哪里需要用这个异常返回,哪里就throw
*/
class ItheimaAgeIllegalException extends Exception{//年龄
public ItheimaAgeIllegalException() {
}

public ItheimaAgeIllegalException(String message) {
super(message);
}
}

/**
* 自定义的运行异常
* 1、继承RuntimeException
* 2、重写RuntimeException的构造器。
* 3、哪里需要用这个异常返回,哪里就throw
*/
class ItheimaAgeIllegalRuntimeException extends RuntimeException{//年龄
public ItheimaAgeIllegalRuntimeException() {
}

public ItheimaAgeIllegalRuntimeException(String message) {
super(message);
}
}