- 什么是异常
有异于常态,在编程当中,阻止当前方法或者作用域,称之为异常。 - 异常的处理以及意义
异常处理有利于正确显示错误信息和错误的地点,以进行下一步的相关操作。使程序继续运行,或者合理合理中断降低损失 -
Java 中的异常体系结构
异常体系
- 异常父类--Throwable
- 主要子类--Error和Exception:
2.1 Error--少见,虚拟机错误,线程死锁,程序会崩溃
2.2 Exception--常见,编码、环境、用户操作等可修复的异常 -
Exception的主要子类:
3.1 检查异常--文件不存在,连接错误等,需要手动添加捕获处理。
3.2 非检查异常--又称运行异常 ,java虚拟机自动抛出并自动捕获。大多是代码问题。
image.png
- 如何处理异常
使用try-catch以及try-catch-finally
try{
//一些会抛出异常的方法
}catch(XXX e){
//处理该异常的代码块,
}catch(XX e){
//可以使用多个catch来处理,但是异常要从小到大使用(子类到父类)
}finally{
//最终要执行的代码
}
以下是一个使用实例:
package study.exception;
public class TryCatch {
public static void main(String[] args) {
TryCatch tc = new TryCatch();
int result = tc.test();
System.out.println("test()方法执行完毕,返回值为"+result);
}
/**
* divider(除数)
* result(结果)
* try-catch捕获while循环
* 每次循环,divide-1,result=result+100/divider
* 如果出现异常,打印“抛出异常了”返回-1
* 否则返回reslut
* @return
*/
public int test(){
int divider = 10;
int result = 100;
try {
//在try里写业务代码
while(divider>-1){
divider--;
result = result+100/divider;
}
System.out.println("try执行完毕,divider = "+divider);
return result;
} catch (Exception e) {
e.printStackTrace();//该方法可以打印出异常信息
//java.lang.ArithmeticException: / by zero
System.out.println("divider = "+divider+" "+"抛出异常了!!!");
System.out.println("catch执行完毕");
return -1;
}finally{
System.out.println("有没有异常finally都可以运行");
System.out.println("finally执行完毕");
}
}
}
结果为
java.lang.ArithmeticException: / by zero
at study.exception.TryCatch.test(TryCatch.java:26)
at study.exception.TryCatch.main(TryCatch.java:6)
divider = 0 抛出异常了!!!
catch执行完毕
有没有异常finally都可以运行
finally执行完毕
test()方法执行完毕,返回值为-1
如果try-catch中没有return,会执行外层的return
解析:try 语句块不可以独立存在,必须与 catch 或者 finally 块同存。
- java中的异常抛出以及自定义异常
throw--动词,在方法体里,显示抛出异常的动作
throws--声明要抛出的异常类型,在方法名参数后 throws异常列表,
//调用会抛出的异常的方法或者 throw new Exception();
可多种类型
如:
public void divide(int a,int b) throws Exception{
if(b=0){
throw new Exception("0不能作为除数");
}
}
- 自定义异常
class 自定义异常类 extends 异常类型(异常父类){}
最简单的实例:
package study.exception;
public class DrunckException extends Exception {
public DrunckException() {
}
public DrunckException(String message) {
super(message);
}
}
解析:Exception 是异常类,自定义异常要继承于 Exception 类或者其子类
- java中的异常链
常常会再捕获一个异常后抛出另外一个异常,并且希望把异常原始信息保存下来,这被称为异常链:
实例:
package study.exception;
public class ChainTest {
/**
* test1():抛出异常"我是异常"
* test2():调用test1(),并捕获"我是异常",并且包装成运行时异常,继续抛出
* main()方法中,调用test2()异常,尝试捕获test2()方法抛出的异常
* @param args
*/
public static void main(String[] args) {
ChainTest ct = new ChainTest();
try {
ct.test2();
} catch (Exception e) {
e.printStackTrace();
}
}
public void test1() throws DrunckException{
throw new DrunckException("test1()的异常");//throws DrunckException
}
public void test2(){
try {
test1();
} catch (DrunckException e) {
RuntimeException newExec = new RuntimeException("test2()的异常");
newExec.initCause(e);
throw newExec;
}
}
}
结果
java.lang.RuntimeException: test2()的异常
at study.exception.ChainTest.test2(ChainTest.java:25)
at study.exception.ChainTest.main(ChainTest.java:12)
Caused by: study.exception.DrunckException: test1()的异常
at study.exception.ChainTest.test1(ChainTest.java:18)
at study.exception.ChainTest.test2(ChainTest.java:23)
... 1 more
捕获到的异常,可以在当前方法的 catch 块中处理,也可抛出给调用者去处理
新的异常包含原始异常的所有信息
也可以简化:
try {
test1();
} catch (DrunckException e) {
// RuntimeException newExec = new RuntimeException("test2()的异常");
// newExec.initCause(e);
RuntimeException newExec = new RuntimeException(e);
throw newExec;
总结
1、处理运行时异常时,采用逻辑去合理规避同时辅助try-catch处理
2、在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常
3、对于不确定的代码,也可以加上try-catch,处理潜在的异常。
4、尽量处理异常,而不是只是简单调用e.printStackTrace()去打印输出。
5、具体如何处理异常,要根据不同的业务需求和异常类型去决定。

