异常
程序员文章站
2022-04-21 21:37:38
...
“因为想过自己想要的生活,所以只有努力,不断地努力”
异常
异常是程序中的⼀些错误,但并不是所有的错误都是异常,并且错误有时候可以避免
异常体系
Throwable 所有错误和异常的⽗类
Error ⽤于指⽰运⾏时环境发⽣的错误(服务器宕机,数据库崩溃等等)
Exception 可处理的异常
JVM默认处理异常⽅式:
- ⾃⼰将问题处理,然后继续运⾏。
- ⾃⼰没有合适的处理⽅式,交给main⽅法的调⽤者JVM来处理,⽽JVM的默认
处理⽅式是将错误信息直接打印到控制台,此时程序停⽌运⾏。
public class Demo01 {
public static void main(String[] args) {
System.out.println(10 / 0);
}
}
异常处理的方式
格式:
try {
可能出现异常的代码
} catch (异常类型 变量名) {
处理异常的代码
} finally {
释放资源代码
}
案例1: 捕获一个异常
public class Demo01 {
public static void main(String[] args) {
Demo01 d = new Demo01();
try {
d.test();
System.out.println(10 / 2);
} catch (ArithmeticException e) {
System.out.println("除数为了0,别这样");
}
}
public void test() {
System.out.println(10 / 0);
}
}
案例2:捕获多个异常
package 异常;
public class Demo05 {
public static void main(String[] args) {
Demo01 d = new Demo01();
int a = 10;
int b = 0;
int[] arr = { 11, 22, 33, 44 };
try {
System.out.println(a / b);
System.out.println(arr[10]);
arr = null;
System.out.println(arr[0]);
// 注意:前面捕获的异常类型不能比后面捕获的异常类型大
} catch (ArithmeticException e) {
System.out.println("除数为了0,别这样");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("你过线了,回去把");
}
}
}
异常分类
编译时异常
编译时异常的java程序必须进⾏显式的处理,否则程序不能通过编译。
运⾏时异常
⽆需显式处理,也可以和编译时异常⼀样进⾏处理,所有的RuntimeException及其⼦类的实例都被称为运⾏时异常。
注意:运⾏时异常实际上就是你的代码错误,请修改你的代码,不需要处理这种异常
案例1:编译时异常
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("xxx.txt");
} catch (FileNotFoundException e) {
System.out.println("文件找不到");
}
}
常⻅⽅法
getMessage(); 获取异常信息,返回字符串
toString(); 获取异常类名和信息,返回字符串
printStackTrace(); 打印异常类名和信息,以及异常出现在程序中的位置,返回值void
案例1
public static void main(String[] args) {
try {
System.out.println(10 / 0);
} catch (Exception e) {
System.out.println(e.getMessage());
System.out.println(e.toString());
e.printStackTrace();
}
}
异常处理的方式
抛出异常
定义功能⽅法时,需要把出现的问题暴露给调⽤者来处理,那么就通过throws在⽅法上标识。
格式:
修饰符 返回值类型 方法名() throws 异常类型 {
}
案例1:
创建Person类
public void setAge(int age) throws Exception {
if (age > 0
age < 150) {
this.age = age;
} else {
System.out.println("年龄不正常");
throw new Exception("年龄不正常");
}
}
测试类
public static void main(String[] args) throws Exception {
Person p = new Person();
p.setAge(-18);
System.out.println(p.getAge());
}
throw关键字
作用:
在⽅法中出现某种情况,程序不能继续运⾏,需要进⾏跳转时,就⽤throw把异常对象抛出.
throws与throw的区别
throws
1.⽤在⽅法声明上⾯,后⾯跟的是异常类型
2.可以跟多个异常类型,⽤逗号隔开
3.表⽰该⽅法可能出现的异常类型,该⽅法的异常由调⽤者来处理
throw
1.⽤在⽅法内,后⾯跟的是异常对象
2.只能抛出⼀个异常对象
3.表⽰抛出异常,由⽅法体内的语句进⾏处理
finally关键字
特点:
- 被finally控制的语句体⼀定会执⾏
- 特殊情况:在执⾏finally语句体之前,jvm退出了
作⽤:⽤于释放资源,在IO流操作和数据库操作中会⻅到
案例一:
public static void main(String[] args) {
try {
System.out.println(10 / 0);
} catch (Exception e) {
System.out.println("除数为0了");
System.exit(0);
return;
} finally {
System.out.println("finally的语句体");
}
}
常见面试题:
1. final,finally和finalize的区别
final可以修饰类,不能被继承
修饰方法,不能被重写
修饰变量,只能赋值一次
finally是try语句中的一个语句体,不能单独使用,用来释放资源
finalize是一个方法,当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
2.static int test() {
int x = 1;
try {
x++;
return x;
} finally {
++x;
return x; 不推荐在finally中使用return
}
}
Output:x=3
3.public abstract class Test {
public static void main(String[] args) {
System.out.println(beforeFinally());
}
public static int beforeFinally(){
int a = 0;
try{
a = 1;
return a;
}finally{
a = 2;
}
}
}
/**output:
1
*/
解析:从结果上看,貌似`finally` 里的语句是在`return` 之后执行的,其实不然,实际上`finally` 里的语句是在在`return` 之前执行的。那么问题来了,既然是在之前执行,那为什么`a` 的值没有被覆盖了?
实际过程是这样的:当程序执行到try{}语句中的return方法时,它会干这么一件事,将要返回的结果存储到一个临时栈中,然后程序不会立即返回,而是去执行finally{}中的程序, 在执行`a = 2`时,程序仅仅是覆盖了a的值,但不会去更新临时栈中的那个要返回的值 。执行完之后,就会通知主程序“finally的程序执行完毕,可以请求返回了”,这时,就会将临时栈中的值取出来返回。这下应该清楚了,要返回的值是保存至临时栈中的。
再来看一个例子,稍微改下上面的程序:
public abstract class Test {
public static void main(String[] args) {
System.out.println(beforeFinally());
}
public static int beforeFinally(){
int a = 0;
try{
a = 1;
return a;
}finally{
a = 2;
return a;
}
}
}
/**output:
2
*/
解析:在这里,finally{}里也有一个return,那么在执行这个return时,就会更新临时栈中的值。同样,在执行完finally之后,就会通知主程序请求返回了,即将临时栈中的值取出来返回。故返回值是2.
扩展:
1. 不管有没有出现异常,finally中的代码都会执⾏
2. 当try和catch中有return时,finally仍然会执⾏。
3. finally是在return后⾯的表达式运算后执⾏的(此时并没有返回运算后的值,⽽是先把要返回的值保存起
来,在finally中没有return新值的情况下,返回值不会改变,仍然是之前保存的值),所有⽅法返回值是
在finally执⾏前就确定了
4. finally中最好不要使⽤return,否则程序会提前退出,返回值重新确定。
⾃定义异常
继承Exception或者RuntimeException,然后编写需要的⽅法即可
案例1:
public class AgeOutOfBoundException extends Exception {
public AgeOutOfBoundException() {
super();
}
public AgeOutOfBoundException(String message) {
super(message);
}
}
异常注意事项
1. ⼦类重写⽗类⽅法时,⼦类的⽅法必须抛出相同的异常或⽗类异常的⼦类
2. 如果⽗类抛出了多个异常,⼦类重写⽗类时,只能抛出相同的异常或它的⼦类,⼦类不能抛出⽗类没有的异
常
3. 如果被重写的⽅法没有异常抛出,那么⼦类的⽅法不能抛出异常,如果⼦类⽅法内有异常发⽣,只能使⽤
try..catch
上一篇: npm install --save @antv/g6报错
下一篇: python3快速入门