7-异常
1、异常的产生
1. 自动抛出异常
由虚拟机自动生成:程序运行过程中,虚拟机检测到程序发生了问题,如果在当前代码中没有找到相应的处理程序,就会在后台自动创建一个对应异常类的实例对象并抛出——自动抛出
2. 手动抛出异常
-
throw 可以抛出运行时异常(RuntimeException)及其子类以及自定义的继承于RuntimeException的异常
-
throw 不能抛出受查异常以及自定义的继承于Exception的受查异常
-
throw 如果要抛出自定义的继承于Exception的受查异常,要结合throws使用
2、异常的处理
1. try-catch-finally
真正的将异常处理掉了
- 使用
try-catch-finally
处理编译时异常,是得程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用try-catch-finally
将一个编译时可能出现的异常,延迟到运行时出现。 - 使用
try-catch-finally
处理运行时异常,使得程序不会因为异常停止,会输出异常信息
try {
//可能出现异常的代码
} catch (ExceptionName1 e) {
//异常处理的相关代码,如:getMessage()、printStackTrace()
} catch (ExceptionName2 e) {
//异常处理的相关代码,如:getMessage()、printStackTrace()
//printStackTrace():打印堆栈跟踪信息
//getMessage():返回错误详细信息(没有跟踪信息只有错误原因)
} finally {
//无论是否异常,都需执行的代码结构,常用于释放资源
}
复制代码
-
用
try
将可能出现异常的代码包起来,在执行过程中,一旦出现异常,就会生成一个对应的异常类 -
生成的异常类会和
catch
中的异常类型进行匹配,匹配到就进入catch
中进行异常的处理 -
一旦处理完成,就会跳出
try-catch
结构 -
catch
中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓 -
catch
中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面 -
finally
(可选的):无论是否异常,都需执行的代码结构,常用于释放资源,像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的
1.1 执行顺序
- 没有return
try {
t();
tt();
} catch (Exception e) {
c();
} finally {
f();
}
m();
//try中没有异常,所以不会执行catch:t() --> tt() --> f() --> m()
//若try中的t()有异常:t() --> c() --> f() --> m()
复制代码
- 有return
/*
任何执行try 或者catch中的return语句之前,都会先执行finally语句, 如果finally中有return语句,那么程序就return了,就不会再执行try或catch中的return语句了。如果finally中没有return语句,当try中没有异常时,如例1.1;当try中有异常时,如例1.2
*/
//1. finally中没有return
//1.1 try中有return,没有异常,
try {
t();
tt();
return 1;
} catch (Exception e) {
c();
return 2;
} finally {
f();
}
m();
//t() --> tt() --> f() --> 1 --> m()
//1.2 try中有return,有异常,catch中有return
try {
t();//有异常
tt();
return 1;
} catch (Exception e) {
c();
return 2;
} finally {
f();
}
m();
//t() --> c() --> f() --> 2 --> m()
//2. finally中有return
//2.1 try中有return,没有异常
try {
t();
tt();
return 1;
} catch (Exception e) {
c();
return 2;
} finally {
f();
return 3;
}
m();
//t() --> tt() --> f() --> 3 --> m()
//2.2 try中有return,有异常,catch中有return
try {
t();//有异常
tt();
return 1;
} catch (Exception e) {
c();
return 2;
} finally {
f();
return 3;
}
m();
//t() --> c() --> f() --> 3 --> m()
复制代码
2. throws + 异常类型
将异常抛给了方法的调用者,并没有真正将异常处理掉
2.1 方法重写
- 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
- 父类的方法没有抛异常,子类重写的方法不能抛异常
- 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果子类重写的方法中有异常,必须使用try-catch-finally方式处理。
3、自定义异常类
3.1 如何自定义异常类
- 继承Exception或其子类,常用RuntimeException
- 提供重载的构造器
- 无参数的构造器
- String Message参数的构造器
3.2 手动抛出异常
public class Exception6 {
public static void main(String[] args) {
Student s = new Student();
//受查异常需要用try-catch处理
//或者再用throws抛出,不然编译器会标红
try {
s.setSex("123");
} catch (SexMismatchException e) {
e.printStackTrace();//SexMismatchException: 性别输入为:“男”或者“女”
}
//由于异常已被处理,所以下面代码会执行
System.out.println(s.getSex());//null
//用try-catch处理运行时异常
try {
s.setAge(200);
} catch (Exception e) {
e.printStackTrace();
}
//由于异常已被处理,所以下面代码会执行
System.out.println(s.getAge());//0
//运行时异常不需要处理,编译器不会标红,在运行时会报出此异常
s.setAge(200);//RuntimeException: 年龄应该在0~130岁之间
//而这里抛出了异常没有处理,所以后面代码不会执行
System.out.println(s.getAge());
}
}
//自定义受查异常
class SexMismatchException extends Exception{
//1. 无参的构造器
public SexMismatchException(){
}
//2. String message参数的构造器
public SexMismatchException(String message){
super(message);
}
}
//自定义运行时异常
class AgeInputException extends RuntimeException{
public AgeInputException(){
}
public AgeInputException(String message){
super(message);
}
}
class Student {
private int age;
private String sex;
public int getAge() {
return age;
}
public void setAge(int age) {
if(age > 0 && age < 130){
this.age = age;
}else{
//运行时异常,throw直接抛出
throw new AgeInputException("年龄应该在0~130岁之间");
}
}
public String getSex() {
return sex;
}
public void setSex(String sex) throws SexMismatchException {
if(sex.equals("男") || sex.equals("女")){
this.sex = sex;
}else{
//受查异常,需要利用throws抛出
throw new SexMismatchException("性别输入为:“男”或者“女”");
}
}
}
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END