第七讲 异常
1 什么是异常?
异常就是不正常。
比如:一个正常人,感冒发烧生病,就是这个人异常了。
当一个人感冒了,没有吃药,表面上没有处理,但是不影响他正常生活,是不是身体内部
的免疫系统帮他处理了这个感冒!
比如一个人得了新冠肺炎,不处理行吗?不处理这个人可能面临生命危险。
这种病毒,人的身体内的免疫系统处理不了,如果不主动处理,就会出事。
比如:在java中,我们进行类型转换的时候,有可能出现类型不匹配,无法转换,强制转的就会发生异常。
举例:
public class ExceptionTest01 {
public static void main ( String[ ] args) {
int res = 100 / 0 ;
System. out. println ( res) ;
System. out. println ( "hello" ) ;
}
}
2 java中的异常是什么?
java中定义了很多异常类,他就是一个普通的类。产生一些普通的对象。
只不过这些类与程序中出现的异常相关。是为了处理异常而开发出来的。
首先,我们来看看异常的继承关系:
注意两个概念:
写代码的时候,编译时报错的异常,就是编译时异常
写代码的时候,编译时没有报错的异常,就是运行是异常(RuntimeException)
3 编译时异常怎么处理?
两种处理方式:
1. 上抛,throws 也就是说,我没能力处理,报给上一个调用我的方法
上一个也可以继续上抛,一直抛到main方法上。main方法再上抛就会抛给JVM
JVM就会中断运行。
对于编译时异常,一直上抛,说明只是把问题抛给了更高一级,并没有实实在在的处理它
2. 捕获异常
try{}catch(){}
也就是说,一旦异常发生,可以上抛,但是在没有到达main方法之前,最好捕捉并处理。
不要将这些异常交给JVM自动处理。
4 处理异常的方式
方式1:上抛 语法格式:throws 异常类的类名
throws关键字出现在方法声明的()后 {之前。
private static void m4() throws FileNotFoundException { 方法体}
编译时异常一定要捕获,一定要处理,如果不做任何处理,编译过不了。
如果一味上抛,一旦出现问题,jvm会终止运行。
异常一旦发生且被捕获之后,程序是不会终止运行的。
打印出来的信息叫做堆栈追踪信息
它是告诉开发人员,问题出在哪里。
e.printStackTrace()这个方法是异常中最重要的一个方法。
一般都使用这个方法,这个方法出现在cath语句块中。
详细介绍try...catch
try: 尝试
catch:捕捉,捕获,抓住
try {
java语句;
}
大括号是一个作用域,在这里面定义的变量,出了这个作用域就失效了。
如果try语句块中没有要处理的异常信息,
catch是一个可以省略的,但是不建议省略。
try只会在有异常发生的情况下才会出现。
如果只有try是不行的。
catch() {}
catch(异常类的变量)
try {
m1();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
m1()方法抛出的异常类型是什么,catch()的参数一定要是这个类型,或者是其父类型。
try...catch的执行过程:
try 语句块中的m1()方法执行,这时候异常发生,那么如果m1()方法后面还有其他的语句,将不会执行。
这时候程序进入到catch语句块中执行,这时候先检查catch()中的参数类型,是否是m1()抛出的异常类型,或者是其父类型(如果是父类型,就是多态的机制),然后打印具体的堆栈追踪信息。
执行完毕后,程序依然向下顺序执行。
如果try语句块中的m1()方法没有发生异常,catch语句快不会被执行。
5 (最重要的部分)手动抛异常:自定义异常
public class NumException extends Exception {
private String message;
public NumException ( ) {
}
public NumException ( String message) {
this . message = message;
}
}
自定义异常类如上:就是固定写法。
成员属性String类型
两个构造,一个无参一个有参
最最重要的:extends Exception
不能继承RuntimeException
手动抛异常:
public class Num {
public void check ( Object object) throws NumException {
if ( object instanceof Integer ) {
System. out. println ( "合法的整数" ) ;
} else {
NumException ex = new NumException ( ) ;
throw new NumException ( "不是合法的整数!" ) ;
}
}
}
注意:一定要有关键字throw 不是throws ,throws 的放在方法( ) 后面
throw 用在方法体内
throw new 要抛的异常类( ) ;
throw new : 配合使用。
测试类:
public class Test {
public static void main ( String[ ] args) {
Num num = new Num ( ) ;
try {
num. check ( "123123123" ) ;
} catch ( NumException e) {
e. printStackTrace ( ) ;
}
}
}
6 如何阅读控制台输出的异常信息
java. io. FileNotFoundException: F: \Is\Study\src\com\tj\exceptionTest\ExceptionTest01. java ( 系统找不到指定的路径。)
at java. io. FileInputStream. open0 ( Native Method)
at java. io. FileInputStream. open ( FileInputStream. java: 195 )
at java. io. FileInputStream. < init> ( FileInputStream. java: 138 )
at java. io. FileInputStream. < init> ( FileInputStream. java: 93 )
at com. tj. exceptionTest. ExceptionTest02. m4 ( ExceptionTest02. java: 45 )
at com. tj. exceptionTest. ExceptionTest02. m3 ( ExceptionTest02. java: 40 )
at com. tj. exceptionTest. ExceptionTest02. m2 ( ExceptionTest02. java: 34 )
at com. tj. exceptionTest. ExceptionTest02. m1 ( ExceptionTest02. java: 28 )
at com. tj. exceptionTest. ExceptionTest02. main ( ExceptionTest02. java: 17 )
一旦发生异常:就是自己的代码写错了。
错就错在自己的代码错了,SUN写的代码不会错。因为他们只定义了异常
抛出了异常,要求我们自己处理。
我们处理异常,但是异常还是发生了,而且报告了位置,那么要找就要找我们自己
写的代码中哪个位置出错了。
但是我们处理了异常,说明程序能够正常往下执行。不会中断。JVM不会终止。
假如我们写的是服务器,服务器就不会down机。
怎么看异常出现在哪里?
1. 看自己写的代码,在打印的堆栈追踪信息中去找
2. 找自己代码部分最上面的一条堆栈追踪信息。
7 总结try–catch
try..catch不能避免异常,只能确保异常发生以后,程序还能正常运行
但是在try代码块中,异常发生之后,这个异常所在位置之后的代码都将不会执行。
这是在try语句块中。
异常发生后,执行catch语句块中的内容,主要是打印堆栈追踪信息,还有一些日志信息
在idea中,遇到编译时异常,直接alt + enter键,使用try..catch..
自定义异常,一定不能继承RuntimeException。一般都是继承Exception
如果知道具体的异常子类,可以直接继承具体的子类。
catch代码块可以有多个,但是其中的参数一定要从小到大,不能前面是父类,后面是子类
父类会覆盖子类。编译器报错。
jdk1.8以后的新特性:简化多个catch代码块带来的代码臃肿
catch (NumException | FileNotFoundException e)
我们建议能精确就精确,有利于代码的可阅读性
异常的主要作用是提高代码的健壮性。
8 finally子句
finally语句块,一定要联合try使用,没有try这个关键字不起作用
不论try中发生了什么事情,finally子句都会执行。没有异常也会执行。
private static int m ( ) {
int i = 100 ;
try {
return i;
} finally {
i++ ;
}
}
返回的i值为100.
具体的做法如下:
private static int m ( ) {
byte i = 100 ;
byte var1;
try {
var1 = i;
} finally {
int var5 = i + 1 ;
}
return var1;
}