一、异常的概念

1.1 概念

异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象,java处理异常的方式是中断处理。

异常并不是语法错误,因为语法错了,编译不会通过,就不会产生字节码文件,根本就无法运行。

1.2 分类

java.lang.Throwable 类是java语言中所有错误或异常的超类。

  • Exception:编译期异常,编译java程序出现的问题。
  • RuntimeException:运行期异常,java程序运行过程中出现的问题
  • Error:错误

异常处理好了,程序可以继续执行;而错误必须修改代码程序才能执行。

异常 - 图1

1.3 异常的产生

异常 - 图2

三、throw

可以在指定的方法中抛出指定的异常。

  1. throw new xxxException("异常产生的原因");

注意:

① throw 关键字必须写在方法内部。

② throw 关键字后边new的对象必须是Exception或者Exception的子类对象。

③ throw 关键字抛出指定的异常对象,我们就必须处理这个异常对象。

  • a.如果throw关键字后边创建的是RuntimeException或者是RuntimeException的子类对象,我们可以不处理,默认交给JVM处理(打印异常对象,中断程序)
  • b.throw关键字后边如果创建的是编译异常(写代码的时候报错),我们就必须处理这个异常,要么throws,要么try…catch。

注意:以后在工作中,我们首先必须对方法传递过来的参数进行合法性校验,如果参数不合法,那么我们就必须使用抛出异常的方式,告知方法的调用者,传递的参数有问题。

可以用Objects.requireNonNull(T obj)方法或者Objects.requireNonNull(T obj,String message)来判断对象是否为空,并打印出空指针异常。

  1. Objects.requireNonNull(obj);
  2. Objects.requireNonNull(obj,"传递的对象的值是null");

四、throws

处理异常对象,把异常对象声明抛出给方法的调用者处理(自己不处理,给别人处理),最终交给JVM处理(中断处理)。

在方法声明时使用:

  1. 修饰符 返回值类型 方法名(参数列表) throws AAAException,BBBException...{
  2. throw new AAAException("产生原因");
  3. throw new BBBException("产生原因");
  4. }

注意:

① throws 挂件自必须写在方法声明处。

② throws关键字后边声明的异常必须是Exception或者其子类。

③ 方法内部如果抛出了多个异常,那么throws后面也必须声明多个异常。如果多个异常对象有子父类关系,那么直接声明父类异常即可。

④ 调用了一个声明抛出异常的方法,我们就必须处理声明的异常,要么继续使用throws声明抛出,交给方法的调用者处理,最终交给JVM;要么使用try…catch自己处理异常。

  1. public class Demo05Throws {
  2. public static void main(String[] args) throws Exception {
  3. readFile("c:\\a.tx");
  4. System.out.println("后续代码");
  5. }
  6. /*
  7. 定义一个方法,对传递的文件路径进行合法性判断
  8. 如果路径不是"c:\\a.txt",那么我们就抛出文件找不到异常对象,告知方法的调用者
  9. 注意:
  10. FileNotFoundException是编译异常,抛出了编译异常,就必须处理这个异常
  11. 可以使用throws继续声明抛出FileNotFoundException这个异常对象,让方法的调用者处理
  12. */
  13. public static void readFile(String fileName) throws FileNotFoundException,IOException{
  14. if(!fileName.equals("c:\\a.txt")){
  15. throw new FileNotFoundException("传递的文件路径不是c:\\a.txt");
  16. }
  17. /*
  18. 如果传递的路径,不是.txt结尾
  19. 那么我们就抛出IO异常对象,告知方法的调用者,文件的后缀名不对
  20. */
  21. if(!fileName.endsWith(".txt")){
  22. throw new IOException("文件的后缀名不对");
  23. }
  24. System.out.println("路径没有问题,读取文件");
  25. }
  26. }

五、try…catch

  1. try{
  2. 可能产生异常的代码
  3. }catch(定义一个异常的变量,用来接收try中抛出的异常对象){
  4. 异常的处理逻辑:产生异常对象之后,怎么处理异常对象,在工作中,会把异常信息记录到一个日志中。
  5. }
  6. ...
  7. catch(异常类名 变量名){
  8. }
  9. //catch语句块可以有多个

注意:

① try中可能会抛出对个异常对象,那么就可以使用多个catch来处理。

② 如果try中产生了异常,那么就会执行catch中的异常处理逻辑,执行完毕catch中的处理逻辑,继续执行try…catch之后的代码;如果try中没有产生异常,那么就不会执行catch中异常的处理逻辑,执行完try中的代码,就继续执行try…catch之后的代码。

六、Throwable类

  1. String getMessage() 返回throwable的简短描述
  2. String toString() 返回此throwable的详细消息字符串
  3. void printStackTrace() JVM打印异常对象,默认此方法,打印的异常信息是最全面的
  1. System.out.println(e.getMessage());
  2. System.out.println(e.toString());
  3. System.out.println(e);

七、finally

无论是否发生异常,都会执行。

  1. try{
  2. }catch(异常类名 变量名){
  3. }
  4. ...
  5. catch(异常类名 变量名){
  6. }
  7. finally{
  8. }

注意:

① finally不能单独使用,必须和try一起使用。

② finally一般用于资源释放(资源回收,无论程序是否出现异常,最后都要资源释放)

③ 如果finally中有return语句,永远返回finally中的结果,避免该情况,不要在finally中写return语句。

八、注意事项

8.1 多个异常的处理

① 多个异常分别处理。

有几个异常就写几个try…catch

② 多个异常一次捕获,多次处理。

一个try,多个catch

如果异常类有子父类关系,那么子类的异常变量必须写在上面,否则会报错。

③ 对个异常一次捕获,一次处理。

一个try,一个catch(因为异常类有子父类关系)

注意:运行时异常可以不抛出也不声明,默认给虚拟机处理。

  1. public class Demo01Exception {
  2. public static void main(String[] args) {
  3. //1. 多个异常分别处理。
  4. try {
  5. int[] arr = {1,2,3};
  6. System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3
  7. }catch (ArrayIndexOutOfBoundsException e){
  8. System.out.println(e);
  9. }
  10. try{
  11. List<Integer> list = List.of(1, 2, 3);
  12. System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
  13. }catch (IndexOutOfBoundsException e){
  14. System.out.println(e);
  15. }
  16. //2. 多个异常一次捕获,多次处理。
  17. try {
  18. int[] arr = {1,2,3};
  19. //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3
  20. List<Integer> list = List.of(1, 2, 3);
  21. System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
  22. }catch (ArrayIndexOutOfBoundsException e){
  23. System.out.println(e);
  24. }catch (IndexOutOfBoundsException e){
  25. System.out.println(e);
  26. }
  27. /*
  28. 一个try多个catch注意事项:
  29. catch里边定义的异常变量,如果有子父类关系,那么子类的异常变量必须写在上边,否则就会报错
  30. ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException
  31. */
  32. try {
  33. int[] arr = {1,2,3};
  34. //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3
  35. List<Integer> list = List.of(1, 2, 3);
  36. System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
  37. }catch (IndexOutOfBoundsException e){
  38. System.out.println(e);
  39. }catch (ArrayIndexOutOfBoundsException e){
  40. System.out.println(e);
  41. }
  42. //3. 多个异常一次捕获一次处理。
  43. try {
  44. int[] arr = {1,2,3};
  45. //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3
  46. List<Integer> list = List.of(1, 2, 3);
  47. System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
  48. }catch (Exception e){
  49. System.out.println(e);
  50. }*/
  51. //运行时异常被抛出可以不处理。即不捕获也不声明抛出。
  52. //默认给虚拟机处理,终止程序,什么时候不抛出运行时异常了,在来继续执行程序
  53. int[] arr = {1,2,3};
  54. System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3
  55. List<Integer> list = List.of(1, 2, 3);
  56. System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
  57. System.out.println("后续代码!");
  58. }
  59. }

8.2 子父类异常

① 如果父类方法抛出了多个异常,子类重写该父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常

② 父类方法没有抛出异常,子类重写父类该方法时也不能抛出异常,此时子类产生该异常,只能捕获处理,不能声明抛出。

九、自定义异常类

  1. public class XXXException Extends Exception/RuntimeException{
  2. 添加一个空参数的构造方法
  3. 添加一个异常信息的构造方法
  4. }

注意:

① 自定义异常类一般都是以Exception结尾,说明该类是个异常类。

② 自定义异常类,必须继承Exception或者RuntimeException

  • a. 继承Exception,那么自定义的异常类就是一个编译期异常,如果方法内部抛出了编译期异常,就必须处理这个异常,要么throws,要么try…catch
  • b. 继承RuntimeException,那么自定义的异常类就是一个运行期异常,无需处理,交给JVM处理(中断处理)
  1. public class RegisterException extends /*Exception*/ RuntimeException{
  2. //添加一个空参数的构造方法
  3. public RegisterException(){
  4. super();
  5. }
  6. /*
  7. 添加一个带异常信息的构造方法
  8. 查看源码发现,所有的异常类都会有一个带异常信息的构造方法,方法内部会调用父类带异常信息的构造方法,让父类来处理这个异常信息
  9. */
  10. public RegisterException(String message){
  11. super(message);
  12. }
  13. }