Throwable类是Java语言中所有异常和错误的超类(可以理解为是仅次于之前学的Object顶级类的超类)。只有作为此类(或其一个子类)的实例的对象有Java虚拟机抛出,或者可以由Java throw语句抛出
Throwable的两个子类的实例'Error'和'异常'通常用于表示出现异常情况
Error:表示严重的问题,合理的应用程序不应该试图捕获(即此时java程序是无能为力的),大多数这样的错误是异常情况。例如硬件层面的问题、内存资源不足等
异常:表示合理应用程序可能想要捕获的条件,这里的条件指的是异常 检查异常:'异常类'和'不是RuntimeException的子类的任何类',检查异常是编译期间必须要处理的,否则程序不会被编译更不会运行
RuntimeException类的异常:是在Java虚拟机的正常操作期间可以抛出的异常的超类。例如索引越界 RuntimeException及其子类的异常:是未经检查的异常,即在编译期间是不需要检查的,出现问题才需要自行检查代码
总结: 1、异常就是程序出现了不正常的情况 2、异常体系指Throwable。Throwable又分为Error、Exception。Exception又分为RuntimeException、非RuntimeException 3、Error是严重问题,不需要处理 4、Exception是异常类,表示程序本身可以处理的问题 5、Exception中的RuntimeException表示在编译期间是不检查的,出现问题后,需要我们回来修改代码 6、Exception中的非RuntimeException表示在编译期间必须处理,否则程序不能被编译,更不能运行
异常的练习
xxxxxxxxxx
package ch13;
public class a_1_1测试 {
public static void main(String[] args) {
methods();
}
public static void methods(){
int[] arr = {1,2,3};//定义数组
System.out.println(arr[1]);//通过索引1访问数组中的元素
//对于数组会有索引越界异常,如下
System.out.println(arr[99]); //报错ArrayIndexOutOfBoundsException
}
}
JVM的默认处理异常方案
默认处理具体做了如下的事情: 1、把异常的名称,异常的原因即异常出现的位置等信息输出在了控制台 2、程序停止执行
JVM默认处理异常方案的练习
x
package ch13;
public class a_2_1测试 {
public static void main(String[] args) {
System.out.println("开始");
method();
System.out.println("结束");
}
public static void method(){
int[] arr = {1,2,3};
System.out.println(arr[99]);
}
/*上面代码的输出如下:
开始
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 99 out of bounds for length 3
at ch13.a_2_1测试.method(a_2_1测试.java:13)
at ch13.a_2_1测试.main(a_2_1测试.java:7)*/
//其中JVM的异常处理如下
//ArrayIndexOutOfBoundsException:异常的名称
//Index 99 out of bounds for length 3:异常的原因
//at ch13.a_2_1测试.method(a_2_1测试.java:13):异常的位置
}
异常处理_trycatch
JVM的默认处理会把程序停止运行,是非常不便于实际开发的。于是,我们来学一下怎么自己处理异常,如下
异常处理 如果程序出现了问题,我们需要自己来处理,有两种方案: 1、使用try...catch... (对于编译时异常,经常使用这种处理方案) 2、使用throws
这里先学习'使用try...catch...'的处理方案,格式如下
xxxxxxxxxx
try{
可能出现异常的代码;
} catch(异常类名 变量名){
异常的处理代码;
}
'使用try...catch...'处理方案的执行流程,如下 1、程序从try里面的代码开始执行 2、出现异常,会自动生成一个异常类对象,该异常类对象奖杯提交给java运行时系统 3、当java运行时系统接收到异常对象时,会到catch中去找匹配的异常类,找到后进行异常的处理 4、执行完毕后,程序还可以继续往下执行
异常处理_trycatch的练习
x
package ch13;
//这节课的测试,要结合上一节课,即'a_2_1测试'一起来看
public class a_3_1测试 {
public static void main(String[] args) {
System.out.println("开始");
method();
System.out.println("结束");
}
public static void method(){
try{
int[] arr = {1,2,3};
System.out.println(arr[99]);//这行出现问题后会产生一个异常类对象。相当于这行new了一个异常,即new ArrayIndexOutOfBoundsException
//上面那行会把异常类对象提交给java的运行时系统。然后运行时系统就会在catch里面找匹配,如果匹配就执行catch里面的代码
} catch(ArrayIndexOutOfBoundsException e){//这个e是对象,即可以调用方法
//System.out.println("你访问的数组的索引不存在"); //这样输出错误提示会比较单调,因为具体的错误并没有在控制台输出
e.printStackTrace(); //这样就即保证了程序继续往下执行,又可以输出具体的异常信息。printStackTrace方法在下一节课有说,即'a_4_0Throwable的成员方法'
}
}
//这节课和上节课的共同点是代码都出现了同样的问题
//这节课和上节课的不同点如下:
//1、上节课的错误由JVM默认处理,不会继续往下执行程序
//2、这节课的错误由我们自己处理,程序可继续往下执行,并且在报错的地方可以自行添加输出信息
}
Throwable的成员方法
Throwable是所有错误和异常的祖宗类(超类),即Throwable的所有子类都可以使用Throwable的成员方法。Throwable的成员方法如下
方法名 | 说明 |
---|---|
public String getMessage() | 返回此Throwable的详细信息字符串 |
public String toString() | 返回此可抛出的简短描述 |
public void printStackTrace() | 把异常的错误信息输出在控制台 |
Throwable成员方法的练习
x
package ch13;
//可结合上一节课的'a_3_1测试'一起理解
public class a_4_1测试 {
public static void main(String[] args) {
System.out.println("开始");
method();
System.out.println("结束");
}
public static void method(){
try{
int[] arr = {1,2,3};
System.out.println(arr[99]);
} catch(ArrayIndexOutOfBoundsException e){
//public void printStackTrace() 把异常的错误信息输出在控制台
//e.printStackTrace(); //该方法是3个方法中输出的异常信息最多的
//public String getMessage() 返回此Throwable的详细信息字符串
//System.out.println(e.getMessage());;//想了解getMessage方法的底层是怎么实现的,可选中getMessage,再按Ctrl+B
//public String toString() 返回此可抛出的简短描述
System.out.println(e.toString());//输出异常原因以及类名,这个方法的输出包含了getMessag输出的内容
}
}
}
编译时异常和运行时异常的区别
java中的异常被分为两大类:'编译时异常'和'运行时异常',也被称为'受检异常'和'非受检异常'
所有的RuntimeException类及其子类被称为'运行时异常',其他的异常都是'编译时异常'
什么是编译时异常:必须显示处理,否则程序就会发生错误,无法通过编译
什么是运行时异常:无需显示处理,也可以和'编译时异常'一样处理
编译时异常和运行时异常区别的练习
x
package ch13;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class a_5_1测试 {
public static void main(String[] args) {
//method();//要调用才会执行。可以发现控制台报错了,这种是运行时异常,我们需要回到自己的代码里进行修改
method2();
}
//------------------------------------------------------------------------------------------------------------
//运行时异常,先注释有需要自行解开
/*public static void method() {
int[] arr = {1, 2, 3};
System.out.println(arr[99]);
}*/
//解决'运行时异常'的方案,如下。对于运行时异常,写方案只是告诉我们哪里出错了,但真正的解决还是我们需要回到自己的代码里进行修改
/*public static void method() {
try {
int[] arr = {1, 2, 3};
System.out.println(arr[99]);
} catch (ArrayIndexOutOfBoundsException e){
e.printStackTrace();
}
}*/ //先注释,需要自行解开
//--------------------------------------------------------------------------------------------------------------
//编译时异常,先注释有需要自行解开
/*public static void method2(){ //可以回去看前面学的Date类,之前我们在学习Date类时经常会对parse进行异常处理
String s = "2022-5-20";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d = sdf.parse(s); //典型的编译时异常,我们需要通过try…catch来处理
System.out.println(d);
}*/
//解决'运行时异常'的方案,如下。对于编译时异常,写方案就能解决报错
public static void method2(){ //可以回去看前面学的Date类,之前我们在学习Date类时经常会对parse进行异常处理
try{
String s = "2022-5-20";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d = sdf.parse(s);
System.out.println(d);
} catch(ParseException e){ //注意ParseException是对应的异常类名称
e.printStackTrace();
}
}
}
异常处理_throws
虽然我们通过try…catch…可以对异常进行处理,但是并不是所有的情况我们都有权限进行异常的处理,也就是说,有些时候可能出现的异常是我们处理不了的,这个时候就需要使用throws这个异常处理方案
throws异常处理方案的格式:
throws 异常类名;
总结: 1、编译时异常必须要进行处理,两种处理方案:try…catch…和throws,如果使用的是throws这种方案,将来谁调用谁处理 2、运行时异常可以不处理,出现问题后,需要我们回来修改代码
异常处理_throws的练习
xxxxxxxxxx
package ch13;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class a_6_1测试 {
public static void main(String[] args) {
System.out.println("开始");
//method(); //这里对应的是36行那里的被注释的代码块
try { //这个try方案才是真正能解决异常的,try的代码是由于14行的快捷键才出现的(也可自己手写)
method2(); //当28行抛出异常后,这里的method2就会报红线。同样也是选中method2,按Alt+enter,点击Surround……
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("结束");
}
//----------------------------------------------------------------------------------------------------
//编译时异常。注意throws ParseException是28行那里按了Alt+enter,点击Add才出现的(也可自己手写)。这个实际就是异常处理的throws方案
public static void method2() throws ParseException {
String s = "2022-5-20";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d = sdf.parse(s); //需要选中parse,按Alt+enter,点击Add……。在之前将过这个快捷键,现在就正式了解是干嘛的
System.out.println(d);
} //注意,这个错误只是抛出,不过在13行那里进行了真正的解决
//-----------------------------------------------------------------------------------------------------
//运行时异常。使用throws时,直接把throws ArrayIndexOutOfBoundsException加到下面那一行。这个实际就是异常处理的throws方案
/*public static void method() throws ArrayIndexOutOfBoundsException{
int[] arr = {1,2,3};
System.out.println(arr[99]);
} //注意,这个错误只是抛出,并没有真正处理。对应的是11行的代码*/ //这部分代码块只是抛出,没有处理,所以注释了,要处理的话在11行使用try就能处理
//------------------------------------------------------------------------------------------------------
//总结:throws只是把异常抛出去(其实就是延迟处理,不是一种具体的处理),并且还会让程序停止运行,并没有解决异常
//如果需要真正处理,就需要使用try…catch。被try处理后,程序不会停止,还会继续运行
}
自定义异常
自定义异常的格式
x
public class 异常类名 extends Exception{
无参构造
带参构造
}
throws和throw的区别,如下
xthrows: throw
1、用在方法声明后面,跟的是异常类名 1、用在方法体内,跟的是异常对象名
2、表示抛出异常,由该方法的调用者来处理 2、表示抛出异常,由方法体内的语句处理
3、表示出现异常的一种可能性,并不一定会发生这些异常 3、执行throw一定抛出了某种异常,即被throw抛出,那一定是异常
例如我们这个打分案例,只要score在0~100就不会发生异常
超出范围就会异常被抛出
自定义异常的练习
x
package ch13;
//注意自定义异常类必须要继承Exception或RuntimeException。Exception是编译时异常,RuntimeException是运行时异常
public class a_7_1自定义异常类 extends Exception {
//无参构造方法。控制台会显示异常名称和异常发生的位置,但异常的原因不会显示
public a_7_1自定义异常类(){}
//带参构造方法
public a_7_1自定义异常类(String message){
super(message); //想深入了解可选中super,按Ctrl+B跟进源码,进去另一个页面后再选中super……。可以知道message是传到Throwable里面了
}
}
xxxxxxxxxx
package ch13;
public class a_7_2Teach {
//需要在下一行用throws把异常类抛出来
public void checkScore(int score) throws a_7_1自定义异常类{
if(score<0 || score>100){ //当小于0或者大于100时,就不适合我们评分,即出现问题了,我们需要把符合if逻辑的错误判断抛出,如下
//throw new a_7_1自定义异常类(); //throw跟的是对象。用于在方法体中抛出错误对象
//上面那行是抛给无参构造方法。控制台会显示异常名称和异常发生的位置,但异常的原因不会显示。所以报错不太具体,我们使用带参,如下
throw new a_7_1自定义异常类("error 请输入0~100的数字"); //带参,可以把报错的原因反馈给用户。注意这里是throw
} else{
System.out.println("分数正常");
}
}
}
x
package ch13;
import java.util.Scanner;
public class a_7_3测试 {
public static void main(String[] args){
while (true) { //这个只是循环,不加循环也行
//键盘录入分数
Scanner sc = new Scanner(System.in);
System.out.println("请输入分数");
int score = sc.nextInt();
//创建Teach类对象
a_7_2Teach t = new a_7_2Teach();
try { //这个try不是我们自己写的,是由于17行的快捷键生成的。当然自己写也可以
//由于我们自定义的异常是编译时异常,所以这行的checkScore会报红线,解决:选中checkScore,按Alt+enter,点击Surr…
t.checkScore(score);
} catch (a_7_1自定义异常类 e) {
e.printStackTrace();
}
System.out.println("-------------------");
//该案例如果我们输入的是[0,100]就不会报错,但是如果输入的是其他就会报错,是因为我们在这个案例继承了我们定义的异常类
}
}
}