异常处理
一、异常机制
Exception:指程序运行过程中出现的一些意外。
-
异常分类:
- 检查性异常:常见的有用户错误引起的异常,比如用户打开一个不存在的文件。
- 运行时异常:最可能被程序员避免的异常,运行时异常可以在编译的时候被忽略。
- 错误ERROR:错误比异常更严重,不容易被发现,比如栈溢出了,这个问题编译的时候查不到。
-
异常体系结构
- JAVA把异常当作对象来处理,定义了一个java.lang.Throwable作为所有异常的超类。
- 在java API中定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception。
-
Error和Exception的区别:
- Error通常是灾难性的致命错误,是程序无法控制和处理的,当出现这些异常时,java虚拟机(JVM)一般会选择终止线程。
- Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能去处理这些异常。
二、异常处理
2.1异常处理关键字
- try、catch、finally、throw、throws
2.2代码举例:
- 没加异常处理
package exception;
public class Test {
public static void main(String[] args) {
int a = 1;
int b = 0;
System.out.println(a/b);
}
}
输出:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at exception.Test.main(Test.java:8)
- 加入异常处理
package exception;
public class Test {
public static void main(String[] args) {
int a = 1;
int b = 0;
System.out.println(a/b);
try{//在try里面相当于监控区域,在这里面的代码块出现异常可以被捕获到
System.out.println(a/b);
}catch(ArithmeticException e){//如果try里面的代码块出现了异常,那就执行这里面的代码
//这个catch里面的参数是捕获的异常类型
System.out.println("程序出现异常,变量b不能为0");
}finally {//不管try里面有没有异常,最终都会执行这里的代码。(善后)
System.out.println("finally");
}//这个finally可以不要,因为它主要是善后,比如一些I/O流,最后要关闭。
}
}
输出:
程序出现异常,变量b不能为0
finally
- 捕获多个异常
package exception;
public class Test {
public static void main(String[] args) {
int a = 1;
int b = 0;
try{
System.out.println(a/b);
}catch(Error error){
System.out.println("Error");
}catch (Exception e){//可以捕获多个异常,这里要注意一点,这三个的顺序,Throwable比Error和Exception都大,要放在最下面,否则那俩就被覆盖了。即捕获多个异常的时候,异常捕获的范围要从小到大。
System.out.println("Exception");
}catch (Throwable t){
System.out.println("Throwable");
}finally {
System.out.println("finally");
}
}
}
输出:
Exception
finally
- 快捷键操作:选中可疑代码Ctrl+Alt+t
变成:
2.3 throw和throws
- throw
package exception;
public class Test {
public static void main(String[] args) {
new Test().test(1,0);
}
public void test(int a,int b){
if (b==0){
throw new ArithmeticException();//主动抛出异常,一般在方法体中使用
}
}
}
输出:
Exception in thread "main" java.lang.ArithmeticException
at exception.Test.test(Test.java:13)
at exception.Test.main(Test.java:6)
关于这个throw什么用:从上面代码中我们可以看到,在方法里我们并没有做除法操作,但是它仍然抛出异常了,所以叫主动抛出异常。
- throws
package exception;
public class Test {
public static void main(String[] args) {
try {//在这里处理异常
new Test().test(1,0);
} catch (ArithmeticException e) {
System.out.println("出现了异常");
}
}
public void test(int a,int b)throws ArithmeticException{//假设在这个方法中处理不了这个异常,可以往外抛出,也就是说这个test方法中如果出现异常,在方法里处理不了那我就把这个异常抛出去让调用这个方法的地方去处理,那么我在主程序中调用的时候就要用try把这个方法括起来然后用catch捕获处理。
System.out.println(a/b);
}
}
输出;
出现了异常
- throw和throws的异同:
- 两者出现位置不同,threw在方法的函数体中,throws在方法函数头。
- 作用不同,throw是程序员自己写的我要抛出什么异常,而throws只是告调用者抛出异常的类型是啥
- 通过这两个关键字都仅仅是抛出了异常但是并没有处理,真正处理还是在函数调用的时候用catch代码块处理的
三、自定义异常
- 自定义异常步骤
- 创建自定义异常类(只要继承Exception就可以)
- 在方法中通过throw关键字抛出异常对象
- 如果在当前抛出的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过关键字throws关键字告诉调用者抛出异常的类型,继续下一步工作
- 在出现异常方法的调用者中捕获并处理异常
package exception.demo02;
public class MyException extends Exception{//自定义异常
private int detail;
public MyException(int a) {
this.detail = a;
}
//toString:异常的打印信息,也就是如果我抛出这个异常了,输出的 信息是啥
//用Alt+insert 选中toString
@Override
public String toString() {
return "MyException{" + "detail=" + detail + '}';
}
}
//测试异常
package exception.demo02;
public class Test {
//可能会存在异常的方法
static void test(int a) throws MyException {
System.out.println("传递的参数为:"+a);
//数字>10就抛出异常
if (a>10){
throw new MyException(a);//抛出异常,也可以在这里捕获
}
System.out.println("ok");//如果不大于10就正常输出没有异常
}
public static void main(String[] args) {
try {
test(11);
} catch (MyException e) {//这个e就是指我这个异常输出的消息
System.out.println("MyException=>"+e);
}
}
}
输出:
传递的参数为:11
MyException=>MyException{detail=11}//可以看到我这里输出的异常信息就是我之前定义的
四、异常总结
- 处理运行异常的时候,采用逻辑去合理规避同时辅助try-catch处理
- 在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常
- 对于不确定的代码,也可以加上一个try-catch,处理潜在异常
- 尽量去处理异常,不要简单的在catch里面打印异常
- 具体如何处理异常,要根据不同的业务需求和异常类型去决定
- 尽量添加finally语句去释放占用的资源。