5 Java异常处理机制

5.1 概念

异常:Java程序运行期出现的错误

异常机制提供了程序退出的安全通道,当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器

5.2 分类

  • 按运行时分类:

    • 运行时异常(RuntimeException

      • 都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)等
      • 这些异常是不可查异常,可以处理(抛出或捕获)也可以不处理
      • 通常是由于编程人员逻辑错误等原因引起,编码过程中程序员应尽量避免
      • 运行时异常将由Java运行时系统自动抛出,允许应用程序忽略运行时异常
    • 非运行时异常(编译异常)

      • RuntimeException以外的异常,类型上属于Exception类及其子类,如IOExceptionSQLException等以及用户自定义的Exception异常
      • 必须进行处理,如果不处理,程序就不能编译通过
  • 按是否可查分类:

    • 可查异常(checked exceptions

      • 编译器要求必须处理(抛出或捕获)的异常
      • 编译不通过时如果不处理会报错
    • 不可查异常(unchecked exceptions

      • 编译器不要求强制处理的异常,出现错误需要修改相应程序,不需要抛出或捕获
      • 编译时不会报错
      • 包括运行时异常(RuntimeException与其子类)和错误(Error
  • 错误(Error):

    • 是程序无法处理的错误,表示运行应用程序中较严重问题,大多数错误与代码编写者执行的操作无关
    • 例如:Java虚拟机运行错误(Virtual MachineError)或当 JVM 内存资源使用完时会现OutOfMemoryError
    • 错误是不可查的,一般它们在应用程序的控制和处理能力之外
  • 异常常用方法

    • e.printStackTrace():打印异常堆栈信息
    • e.getMessage():获取异常信息,如果没有为null
    • e.getLocalizedMessage():一般由子类重写加入特定语言环境信息,默认与getMessage()相同
  • 异常与重写

    • 重写的方法必须和被重写的方法抛出的异常相同,或者不抛出,不能抛出被重写方法异常的父类或子类

5.3 异常的捕获和处理

5.3.1 抛出异常

  • 使用throw 异常类()抛出异常
  • 使用throws在方法上声明抛出的异常,可以是多个
  • 异常抛出后并没有真正处理异常,需要调用方进行处理,如果调用方不能处理,则继续向上抛出

5.3.2 捕获异常

  • 使用try包裹可能出现异常的代码
  • 使用catch捕获对应的异常对象,可以有多个
  • finally中的代码不管有没有异常,最终都会被执行,finally可以省略
  • catch到异常后,一定要做出处理,养成良好编程习惯,不要把异常吞掉
  • catch多个异常时,注意顺序,应该先catch小类型,再父类型,如果是同级别的异常类,则不用注意顺序

5.3.3 代码示例

  1. /**
  2. * 异常体系
  3. */
  4. public class ExceptionSys {
  5. public static void main(String[] args) {
  6. // 常见异常
  7. commonExceptions();
  8. // 当调用异常的方法时,需要进行捕获或者继续抛出
  9. try {
  10. testThrow(1, 0);
  11. } catch (Exception e) {
  12. // e.printStackTrace();
  13. System.out.println(e.getMessage());
  14. System.out.println(e.getLocalizedMessage());
  15. }
  16. testTryCatch();
  17. }
  18. // 常见异常
  19. public static void commonExceptions() {
  20. // NullPointerException : 空指针异常
  21. byte[] bt = null;
  22. System.out.println(bt[1]);
  23. // ArrayIndexOutOfBoundsException : 数组下表越界异常
  24. byte[] btt = new byte[2];
  25. System.out.println(btt[3]);
  26. // ArithmeticException : 算数异常
  27. int a = 10, b = 0;
  28. int c = a/b;
  29. }
  30. // 抛出异常
  31. public static void testThrow(int a, int b) throws Exception {
  32. if (b == 0)
  33. throw new Exception(); // 也可以抛出确定的异常ArithmeticException或该异常的父类,如 throw new Exception();
  34. int c = a/b;
  35. System.out.println(c);
  36. }
  37. /*
  38. * 注意抛出异常的顺序,父类放在最后,如果父类放在上面,会先进入父类,达不到想要的效果
  39. * 也可以不catch子类,直接catch父类异常
  40. */
  41. public static void testTryCatch() {
  42. try {
  43. byte[] bt = null;
  44. System.out.println(bt[1]);
  45. byte[] btt = new byte[2];
  46. System.out.println(btt[3]);
  47. } catch (NullPointerException e){
  48. System.out.println("空指针异常");
  49. } catch (ArrayIndexOutOfBoundsException e){
  50. System.out.println("数组下标越界异常");
  51. } catch (Exception e){
  52. System.out.println("异常...");
  53. } finally {
  54. System.out.println("执行了finally");
  55. }
  56. }
  57. }

5.4 自定义异常

5.4.1 方法

  • 继承一个异常父类

    • 如果说自定义异常是编译期异常那么继承Exception
    • 如果说自定义异常是运行期异常那么继承RuntimeException
    • 或者根据情况继承其他Exctption
  • 添加构造方法

    • 可以传入异常参数信息,也可以不写参数

5.4.2 代码示例

  1. /**
  2. * 自定义异常
  3. */
  4. public class CustomException {
  5. public static void main(String[] args) {
  6. Bank bank = new Bank();
  7. try {
  8. bank.getMoney(100, 1000);
  9. } catch (NoMoneyException e) {
  10. e.printStackTrace(); // 打印异常堆栈信息
  11. System.out.println("异常信息:" + e.getMessage()); // 获取异常信息
  12. System.out.println(e.getLocalizedMessage()); // 一般由子类重写加入特定语言环境信息,默认与getMessage()相同
  13. // 其他相关处理...
  14. }
  15. }
  16. }
  17. class Bank {
  18. public void getMoney(double totalMoney, double getMoney) throws NoMoneyException {
  19. if (totalMoney < getMoney) {
  20. throw new NoMoneyException("余额不足...");
  21. } else {
  22. System.out.println("取款成功...");
  23. }
  24. }
  25. }
  26. // 自定义异常类
  27. class NoMoneyException extends Exception {
  28. // 自定义异常类中还可以进行其他操作,如传入一些相关参数,定义其他处理方法等
  29. public NoMoneyException(String msg) {
  30. super(msg); // 调用父类带参构造方法可以传入异常信息
  31. }
  32. }
  33. class Xbank extends Bank {
  34. /*
  35. * 重写的方法必须和被重写的方法抛出的异常相同,或者不抛出
  36. * 不能抛出被重写方法异常的父类或子类
  37. */
  38. @Override
  39. public void getMoney(double totalMoney, double getMoney) throws NoMoneyException {
  40. // super.getMoney(totalMoney, getMoney);
  41. }
  42. }