0%

异常

异常

第十二章 异常

异常基本介绍

  • Java 语言中,将程序执行中发生的不正常行为称为“异常”。(开发过程中语法错误和逻辑错误不是异常)

    执行过程中所发生的异常事件可以分为两大类:

    1. Error(错误) : Java虚拟机无法解决的严重问题。如 : JVM系统内部错误、资源耗尽等严重情况。比如 : StackOverflowError[栈溢出]和 OOM(out of memory),Error 是严重错误,程序会崩溃。
    2. Exception : 其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如空指针访问、试图读取不存在的文件、网络连接中断等等。Exception 分为两大类 : 运行时异常(程序运行时发生的异常)编译时异常(编程时,编译器检查出的异常)

★异常体系图

![](../../../../../Running Noob/计算机/Typora笔记/笔记-git仓库/Java-notebook/img/Java/C12-1.jpg)

  • 异常分为两大类:
    • 运行时异常(RuntimeException):编译器不要求强制处置的异常,一般是指编程时的逻辑错误,是程序员应该避免其出现的异常。java.lang.RuntimeException 类及它的子类都是运行时异常。
    • 编译时异常:是编译器要求必须处理的异常。

五大运行时异常

NullPointerException
  • 空指针异常:当应用程序试图在需要对象的地方使用 null 时,抛出该异常。
ArithmeticException
  • 数学运算异常:当出现异常的运算条件时,抛出该异常,例如,除数为 0 时。
ArrayIndexOutOfBoundsException
  • 数组下标越界异常:用非法索引访问数组时抛出的异常,如果索引为负或大于等于数组大小,则该索引为非法索引。
ClassCastException
  • 类型转换异常:当试图将对象强制转换为不是实例的子类时,抛出该异常。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    package com.f.chapter12.exception_;

    public class ClassCastException_ {
    public static void main(String[] args) {
    A a = new B(); //父类的变量指向子类的对象 -> 向上转型
    B b = (B)a; //向下转型
    //C c = (B)a; //ClassCastException
    }
    }

    class A {
    }

    class B extends A {
    }

    class C extends A {
    }
NumberFormatException
  • 数字格式不正确异常:当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常 => 使用该异常我们可以确保输入的是满足条件的数字。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package com.f.chapter12.exception_;

    public class NumberFormatException {
    public static void main(String[] args) {
    String s1, s2;
    s1 = "1234";
    s2 = "comf";
    System.out.println(Integer.parseInt(s1)); //输出1234
    System.out.println(Integer.parseInt(s2)); //异常:NumberFormatException
    }
    }

★异常处理机制

  • 异常处理就是当异常发生时,对异常处理的方式。

    1. try-catch-finally:程序员在代码中捕获发生的异常,自行处理。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      try{
      //可能有异常的代码
      }catch(Exception e){
      //捕获到异常
      //当异常发生时,系统将异常封装成Exception对象e,传递给catch,得到异常对象后,程序员自己处理
      //注意:如果没有发生异常,catch代码块不执行
      }finally{
      //不论try代码块是否发生异常,都会执行finally代码块
      //所以通常将释放资源的代码放在finally里
      }
      • 注:在 IDEA 中,可以将想要 try-catch-finally 的代码块选中,然后按快捷键 ctrl+alt+t 来快捷添加 try-catch-finally
    2. throws:将发生的异常抛出,交给调度者(方法)来处理,最顶级的处理者就是 JVM(输出异常信息,退出程序)。

    注意:try-catch-finallythrows 二选一,不要一起用。如果程序员既没有用 try-catch-finally、也没有用 throws ,则默认使用 throws

try-catch
  • Java 提供 try 和 catch 块来处理异常。try 块用于包含可能出错的代码,catch 块用于处理 try 块中发生的异常。可以根据需要在程序中有多个 try…catch 块。

    基本语法:

    1
    2
    3
    4
    5
    6
    7
    try{
    //可疑代码
    //将异常生成的对应的异常对象,传递给catch块
    }catch(异常){
    //对异常的处理
    }
    //如果没有finally,语法可以通过
  • try-catch 注意事项:

    1. 如果异常发生了,则异常发生后面的代码不会执行,直接进入到 catch

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      package com.f.chapter12.try_;

      public class TryCatchDetail {
      public static void main(String[] args) {
      try {
      //用ctrl+alt+t快捷键快速添加try-catch块
      String s = "com";
      int num = Integer.parseInt(s);
      //如果异常发生了,则异常发生后面的代码不会执行,直接进入到catch块
      System.out.println("数字 = " + num);
      } catch (NumberFormatException e) {
      System.out.println("异常信息:" + e.getMessage());
      }
      System.out.println("程序继续执行...");
      }
      }

      输出结果为:

      1
      2
      3
      4
      异常信息:For input string: "com"
      程序继续执行...

      进程已结束,退出代码0
    2. 如果异常没有发生,则顺序执行 try 的代码块,不会进入到 catch

    3. 如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等),则使用 finally

    4. 可以有多个 catch 语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前(否则会报错),比如 Exception 在后,NullPointerException 在前,**如果发生异常,只会匹配一个 catch**。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      package com.f.chapter12.try_;

      public class TryCatchDetail2 {
      public static void main(String[] args) {
      try{
      String s = null;
      System.out.println(s.length());
      int i = 10 / 0;
      }catch(NullPointerException e){
      System.out.println("空指针异常...");
      System.out.println("错误原因为:" + e.getMessage());
      }catch(Exception e){
      System.out.println("其他异常...");
      System.out.println("错误原因为:" + e.getMessage());
      }finally{
      System.out.println("不论是否发生异常,一定会执行......");
      }
      System.out.println("程序继续执行...");
      }
      }

      输出结果为:

      1
      2
      3
      4
      空指针异常...
      错误原因为:null
      不论是否发生异常,一定会执行......
      程序继续执行...
    5. 可以进行 try-finally 配合使用,这种用法相当于没有捕获异常,因此如果发生了异常,则程序在执行完 finally 块后会直接崩掉

      应用场景:执行一段代码之后,不管是否发生异常,都必须执行某个业务逻辑。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      package com.f.chapter12.try_;

      public class TryCatchDetail3 {
      public static void main(String[] args) {
      try{
      String s = null;
      System.out.println(s.length());
      }finally{
      System.out.println("不论是否发生异常,一定会执行......");
      }
      System.out.println("程序继续执行...");
      }
      }

      输出结果为:

      1
      2
      3
      4
      5
      不论是否发生异常,一定会执行......
      Exception in thread "main" java.lang.NullPointerException
      at com.f.chapter12.try_.TryCatchDetail3.main(TryCatchDetail3.java:7)

      进程已结束,退出代码1
    6. finally 块中的代码是一定要执行的,即使在 try 块或 catch 块中有 return 语句,也还是会执行 finally 块中的代码,可以理解为 finally 的优先级要高于 return

  • try-catch-finally 执行顺序小结:

    1. 如果没有出现异常,则执行 try 块中所有语句,不执行 catch 块中语句,如果有 finally ,最后还需要执行 finally 里面的语句;
    2. 如果出现异常,try 块中异常发生后,try 块剩下的语句不再执行,将执行 catch 块中的语句,如果有 finally,最后还需要执行 finally 里面的语句。
throws
  • 如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理

    在方法声明中用 throws 语句可以声明抛出异常的列表,throws 后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package com.f.chapter12.throws_;

    public class Throws01 {
    public static void main(String[] args) {

    }

    public void f1() throws NullPointerException, ArithmeticException, NumberFormatException{
    //f1抛出了三种运行时异常
    }
    }
  • throws 注意事项:

    1. 对于编译异常,程序中必须处理,比如 try-catch 或者 throws
    2. 对于运行时异常,程序中如果没有处理,默认就是 throws 的方式处理
      • 在实际开发中,我们可以这样处理:将编译异常用运行时异常抛出,这时调用者可以选择捕获该异常,也可以选择默认处理该异常,比较方便。
    3. 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常类型的子类型
    4. throws 过程中,如果有方法 try-catch,就相当于处理异常,就可以不必 throws

自定义异常

  • 当程序中出现了某些“错误”,但该错误信息并没有在 Throwable 子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息。

  • 自定义异常的步骤:

    1. 定义类:自定义异常类名(程序员自己写),继承 Exception 或 RuntimeException;
    2. 如果继承 Exception,则属于编译异常;
    3. 如果继承 RuntimeException,则属于运行异常(一般来说,继承 RuntimeException,以便于使用默认的 throws 处理方式)。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    package com.f.chapter12.customexception_;

    public class CustomException {
    public static void main(String[] args) {
    int age = 10;
    //要求年龄范围在18-120之间,否则抛出一个自定义异常
    if (!(age >= 18 && age <= 120)) {
    throw new AgeException("年龄需要设置在18-120之间...");
    }
    System.out.println("年龄范围正确...");
    }
    }

    class AgeException extends RuntimeException {
    public AgeException(String message) {
    super(message);
    }
    }
throw和throws
意义位置后面跟的东西
throws异常处理的一种方式方法声明处异常类型
throw手动生成异常对象的关键字方法体中异常对象
---------------The End---------------