目录
一. 异常的概念
二. 异常的体系结构
三. 异常的分类
三. 异常的处理
3.1 异常的抛出throw
3.2. 异常声明throws
3.3 捕获并处理try-catch
finally
3.4异常的处理流程
四. 自定义异常类
System . out . println ( 10 / 0 );// 执行结果Exception in thread "main" java . lang . ArithmeticException : / by zero
2. 数组越界异常
int [] arr = { 1 , 2 , 3 };System . out . println ( arr [ 100 ]);// 执行结果Exception in thread "main" java . lang . ArrayIndexOutOfBoundsException : 100
3. 空指针异常
int [] arr = null ;System . out . println ( arr . length );// 执行结果Exception in thread "main" java . lang . NullPointerException
点进去任意一个异常, 我们发现:
从上述代码中可以看到,java中不同类型的异常,都有与其对应的类来进行描述
异常可能在编译时发生,也可能在程序运行时发生,根据发生的时机不同,可以将异常分为:
1. 编译时异常
在程序编译期间发生的异常,称为编译时异常,也称为受检查异常(Checked Exception)
例:
我们可以通俗的来理解, 在编写代码的过程中, 出现了红色的波浪线, 此时的异常就叫做编译时异常或受查异常.
2. 运行时异常
在Java中,可以借助throw关键字,由程序猿抛出一个指定的异常对象,将错误信息告知给调用者。具体语法如下:
throw new XXXException("异常产生的原因");
一般情况下, 通过throw抛出的是 自定义的异常, 可以自己通过类定义异常并抛出
例:实现一个获取数组中任意位置元素的方法。
public static int getElement ( int [] array , int index ){if ( null == array ){throw new NullPointerException ( " 传递的数组为 null" );}if ( index < 0 || index >= array . length ){throw new ArrayIndexOutOfBoundsException ( " 传递的数组下标越界 " );}return array [ index ];}public static void main ( String [] args ) {int [] array = { 1 , 2 , 3 };getElement ( array , 3 );}
修饰符 返回值类型 方法名 ( 参数列表 ) throws 异常类型 1 ,异常类型 2 ...{}
意思为:在这个方法中, 可能会包含这些异常, 告诉调用这个方法的人也就是程序猿去处理这些异常
如果程序猿不对异常进行处理, 那么就会交给JVM处理, 程序就会立刻停止.
【注意事项】
因为ArithmeticException是RuntimeException的子类, 所以只用写父类即可, 即:
4. 调用声明抛出异常的方法时,调用者必须对该异常进行处理,或者继续使用throws抛出
把光标方法波浪线处, 使用Alt+Enter 可以使用快捷键
这里的Exception是包含两种类型, 编译时异常和运行时异常, 所以编译器默认调用func()引发的是编译时异常 在main方法后也加上throw Exception, 此时才可能会变成运行时异常, 上JVM处理
try {// 将可能出现异常的代码放在这里} catch ( 要捕获的异常类型 e ){// 如果 try 中的代码抛出异常了,此处 catch 捕获时异常类型与 try 中抛出的异常类型一致时,或者是 try 中抛出异常的基类时,就会被捕获到// 对异常就可以正常处理,处理完成后,跳出 try-catch 结构,继续执行后序代码}[ catch ( 异常类型 e ){// 对异常进行处理// 异常的处理方式//System.out.println(e.getMessage()); // 只打印异常信息//System.out.println(e); // 打印异常类型:异常信息e . printStackTrace (); // 打印信息最全面} ]// 后序代码// 当异常被捕获到时,异常就被处理了,这里的后序代码一定会执行// 如果捕获了,由于捕获时类型不对,那就没有捕获到,这里的代码就不会被执行注意:1. [] 中表示可选项,可以添加,也可以不用添加2. try 中的代码可能会抛出异常,也可能不会
例:
try中的代码发生数组越界, 通过数组越界异常进行捕捉, 所以捕捉到了, 就可以对异常进行处理, 处理后跳出try-catch结构, 继续执行后续代码, 所以运行结果为:
若捕捉的是空指针异常:
即并未捕捉到, 所以就没有处理数组越界异常, 则交给JVM处理, 程序将立刻停止, 什么也不会打印
想要捕获数组越界异常, 继续catch, 自动匹配
第三种写法:(不推荐)
注:
1. 在try中发生异常后的代码不会被执行
语法格式:
try {// 可能会发生异常的代码} catch ( 异常类型 e ){// 对捕获到的异常进行处理} finally {// 此处的语句无论是否发生异常,都会被执行到}// 如果没有抛出异常,或者异常被捕获处理了,这里的代码也会执行
未发生异常:
体会资源回收:
另一种写法:
光标放在try上, Alt+Enter
注意:finally中的代码一定会执行的,一般在finally中进行一些资源清理的扫尾工作。
// 下面程序输出什么?public static void main ( String [] args ) {System . out . println ( func ());}public static int func () {try {return 10 ;} finally {return 20 ;}}//20
首先了解一个概念:调用栈
调用栈:
看下述代码:
在main方法中调用了func(), 在func()中出现了数组越界异常, 但是在func()方法中并没有处理异常, 于是沿着沿着调用栈向上传递到main方法中, 发现在main方法中处理了该异常, 所以不会交给JVM处理, 输出的结果为:
此时, 虽然我们可以很快的找到错误所在, 但代码一多, 就很难找到了, 所以, 我们要自定义异常类来帮助我们更快找到错误.
自定义异常通常会继承自 Exception 或者 RuntimeException继承自 Exception 的异常默认是受查异常继承自 RuntimeException 的异常默认是非受查异常
自定义异常类:
接下来, 通过throw自己抛异常
虽然, 我们抛出了异常, 但是为了使程序正常运行, 我们需要对异常进行处理:
今天的分享就到这里, 谢谢大家的点赞支持!!