运行时异常和编译异常

1.概念:

Java中将程序执行中发生的不正常情况称为异常(Exception)


2.分类

  • Error(错误):JVM无法解决的严重问题,程序会崩溃,比如JVM系统内部错误、资源耗尽等
  • Exception:因编程错误等外在因素导致的一般性问题,可以使用针对性代码进行处理,如空指针访问、网络连接中断等,Exception可以分为两大类:
    • 运行时异常:编译器检测不出,是java.lang.RuntimeException类及其子类,一般是指编程时的逻辑错误,可以不作处理,若全部处理可能会影响代码的可读性和运行效率
    • 编译时异常:编译器要求必须处置的异常,否则代码不能通过编译
  • 异常体系图:

运行时异常和编译异常


3.常见运行时异常

  • NullPointerException:空指针异常,当应用程序试图在需要对象的地方出现null时抛出该异常
  • ArithmeticException: 数学运算异常,当出现异常的运算条件时抛出此异常
  • ArrayIndexOutOfBoundsException: 数组下标越界异常,用非法索引访问数组时抛出的异常
  • ClassCastException :类型转换异常,当试图将对象强制转换为不是实例的子类时抛出该异常
  • NumberFormatException:数字格式不正确异常,当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时抛出该异常

4.常见编译异常

  • SQLException:操作数据库时查询表可能发生的异常

  • IOException:操作文件时发生的异常

  • FileNotFoundException:操作不存在文件时发生的异常

  • ClassNotFoundException:加载类而类不存在时发生的异常

  • EOFException:操作文件到文件末尾发生异常

  • IllegalArguementException:参数异常


5.异常处理

  • 概念:当异常发生时对异常处理的方式

  • 处理方式:

    • try-catch-finally:程序员在代码中捕获发生的异常并自行处理

      try {
          // 可能有异常的代码
      }catch (Exception e){
          // 1.异常发生时将异常封装为Exception e传递给catch
          // 2.得到该对象后程序员自己处理
          // 3.如果没有发生异常catch代码块不执行
      }finally {
          // 不管try代码块是否发生异常都要执行finall代码块
          // 一般用于释放资源
          // 可以只有try-catch部分
      }
      
      
      • 异常发生后,异常部分后面的代码不会执行(不是必须将try代码块全部执行,而是try代码块中发生异常后面的代码不会执行)而是直接进入到catch代码块,注意try-catch代码块后面的代码还是会执行(除非未正确捕获或者在catch代码块中return了):
      try {
          String str = "psj";
          int a = Integer.parseInt(str);
          System.out.println(a);  // 该行代码不会执行
      } catch (NumberFormatException e) {
          e.printStackTrace();
      }
      System.out.println("程序继续...");  // 这一行代码还是会执行
      
      • 可以有多个catch语句,但是父类异常在后,子类异常在前。如果发生异常只会匹配一个catch:
      try {
          String str = "psj";
          int a = Integer.parseInt(str);
          System.out.println(a);
      } catch (NumberFormatException e) {
          e.printStackTrace(); // 执行该代码块
      } catch (Exception e) {
          e.printStackTrace();  // 不会再去执行该代码块
      }
      
      • try-finally配合使用相当于没有捕获异常,所以如果出现异常会抛出异常,并没有自己处理,然后执行finally代码块

    • throws:如果方法可能发生某种异常但是无法确定如何处理该异常,可以将发生的异常抛出并交给方法的调用者处理,最*的处理者为JVM:

      public static void test() throws FileNotFoundException {
          FileInputStream f = new FileInputStream("psj.txt");
      }
      
      • throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类
      • throws后面可以是一个异常列表
      • try-catch-finallythrows二选一
      • 程序员没有显示处理异常,默认使用throws抛出异常

    运行时异常和编译异常

  • 注意事项:

    • 编译异常必须处理,即显示使用throwstry-catch

    • 对于运行时异常,如果程序没有处理默认是throws方式处理

    • 子类重写父类方法时,抛出的异常类型要么和父类抛出的一致,要么为父类抛出异常类型的子类

  • 自定义异常:程序中的错误信息没有出现在Throwable子类中描述处理,此时需要自己设计异常类用于描述该错误信息

    • 定义类:异常类继承ExceptionRuntimeException(继承Exception属于编译异常,继承RuntimeException属于运行异常),一般继承RuntimeException(因为编译异常必须要处理)
    int age = 180;
    //要求范围在 18 – 120 之间,否则抛出一个自定义异常
    if(!(age >= 18 && age <= 120)) {
        //通过构造器设置信息
        throw new AgeException("年龄需要在 18~120 之间");
    }
    System.out.println("你的年龄范围正确.");
    //-----------自定义异常类------------
    class AgeException extends RuntimeException{
        public AgeException(String message) {
            System.out.println(message);
        }
    }
    
  • throw和throws的区别:

意义 位置 后面跟的东西
throws 异常处理的一种方式 方法声明处 异常类型
throw 手动生成异常对象的关键字 方法体中 异常对象
try {
    if (args.length != 4){
        // 该行代码生成一个异常,因为try代码块中出现异常,所以又去执行catch代码块
        throw new ArrayIndexOutOfBoundsException("参数个数不对");   
    }
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println(e.getMessage());
}

tips:

  • 为什么try-catch-finally外的代码还可以执行?因为使用异常捕获的目的就是为了让程序继续正常执行

  • 既然try-catch外的代码块在出现异常后依旧可以执行,为什么还需要finally代码块?因为catch并不能保证一定能捕获到正确的异常,会导致后续代码无法执行:

try {
    String str = "psj";
    int a = Integer.parseInt(str);
    System.out.println(a);
} catch (ArrayIndexOutOfBoundsException e) {  // 异常捕获错误,这里是类型转换异常却捕获的是数组越界
    e.printStackTrace();
}
System.out.println("程序继续...");
  • try/catch代码块中如果有return语句,还是会去执行finally代码块,如果finally中有return语句就执行finally的return语句,没有就执行try/catch代码块中的return语句
System.out.println("执行test方法后,i=" + test());
//--------------test方法--------------
public static int test() {
    int i = 0;
    try {
        String str = "psj";
        int a = Integer.parseInt(str);
        return i;
    } catch (NumberFormatException e) {
        return ++i;  // 执行++i后i=1,但是不会执行return,而是必须执行finally代码块再执行return
    } finally {
        ++i;  // 这个i是上面++i后的i值,所以该步++i后变为2
        System.out.println("执行finally代码块后,i=" + i);
        return 2
    }
}
// 最后结果:
执行finally代码块后,i=2
执行test方法后,i=1

上一篇:istio1.6.14


下一篇:第2篇----Istio架构概述篇