欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaSE 异常抛光解析

程序员文章站 2022-03-30 21:50:06
异常 异常指的是程序中的不正常现象,一般异常都是由第三方数据的使用造成的。java中每种异常现象都会有一个对应的异常类。java对异常的处理方式就是终止程序。异常机制其实是为了帮助我们找到程序中的问题。异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行。 异常体系 jav ......

异常

异常指的是程序中的不正常现象,一般异常都是由第三方数据的使用造成的。java中每种异常现象都会有一个对应的异常类。java对异常的处理方式就是终止程序。异常机制其实是为了帮助我们找到程序中的问题。异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行。

异常体系

java将程序中遇到的每一种异常现象都封装成一个对应的异常类。然后将众多的异常抽取成一个异常体系。而整个异常系统又分为: 错误 和 异常两种现象。

  • java.lang.throwable:异常体系的顶层父类。其下有两个子类:
    • java.lang.error: 错误体系的顶层父类。严重的错误error,无法处理,只能预先避免,好比绝症。
    • 比如开辟数组空间的个数过多,导致内存不够使用。这不是代码的问题,而是硬件不足造成的。
    • java.lang.exception:异常体系中的顶层父类。程序中的异常就是指java.lang.exception。
    • 程序中一旦产生了异常的现象,程序开发人员可以通过代码纠正(就好比生活中身体出现异常,可以通过药物或其他方式进行治疗)。异常是必须要处理的(好比发烧、感冒、阑尾炎)。

小结

throwable是异常体系的根类。针对于程序中的异常,分为:错误(error)和异常(exception)。

error:无法处理,尽量避免。

exception:必须处理。

异常的产生过程解析

当我们操作了数组不存在的下标时,程序会产生一个数组索引越界异常arrayindexofboundsexception。我们通过图解来解析下异常产生的过程。

步骤

  1. 创建一个数组的工具类,类中定义静态方法getelement(),通过提供的数组和下标获取对应的元素。
  2. 创建测试类,在类中定义数组,开辟空间个数3。
  3. 通过数组工具类名调用获取数组元素的方法,并传递创建的数组和4下标。
  4. 运行程序,查看结果。

实现

工具类

public class arraytools {
    // 对给定的数组通过给定的角标获取元素。
    public static int getelement( int[] arr, int index ) {
        int element = arr[index];
        return element;
    }
}

测试类

public class exceptiondemo {
    public static void main(string[] args) {
        int[] arr = { 34, 12, 67 };
        int num = arraytools.getelement(arr, 4)
        system.out.println("num = " + num);
        system.out.println("over");
    }
}

上述程序执行过程图解:
JavaSE 异常抛光解析

小结

当程序中的数据产生异常之后,jvm会识别当前异常。然后将异常的信息进行封装,抛给程序的调用者,让调用者基于获取的异常信息进行处理。而如果没有对异常进行处理,则异常最后会由jvm进行处理。jvm处理的方式就是终止程序,并将异常的信息打印到控制台。

异常分类和处理

目标

程序中需要开发人员处理的异常指的是exception,这类异常一旦出现,我们就要对代码进行更正,修复程序。

异常(exception)的分类:分为 编译时期异常 和 运行时期异常。

  • 编译时期异常:在编译时期,就会检查。如果没有处理异常,则编译失败。( 如日期格式化异常 )
    • exception :编译时期异常顶层父类。除特殊的子类外,其下所有子类都属于编译时期异常类。
  • 运行时期异常:在运行时期,检查异常。运行中发现异常则程序停止运行。编译时期,不会被编译器检测。
    • runtimeexception :exception的一个特殊子类,运行时期异常顶层父类。其下的所有子类都属于运行时期的异常类。如:下标越界。
  • 异常的处理
    • 编译时期异常:编译时就会编译报错,因此必需要处理。只有处理之后才能编译成功,产生class文件。然后才能够让程序运行。
    • 运行时期异常:编译时期不会检查,运行时期检测。如果运行时真的出现了异常现象jvm会结束程序。针对于运行时期异常:可以处理,也可以不用处理,一般不处理。

步骤

  1. 在演示异常的类中创建意思日期字符串。
  2. 创建dateformat对象,并调用parse()方法解析日期字符串(编译异常)
  3. 对比分析编译时期和运行时期异常类。

实现

public class exceptiondemo {
    public static void main(string[] args) {
        int[] arr = { 34, 12, 67 };
        /*
            运行时期的异常,只有在运行时才会检测。编译时期不会检测。
         */
        int num = arraytools.getelement(arr, 4);
        system.out.println("num = " + num);

        // 创建日期字符串
        string time = "2018-12-12";
        // 创建dateformat对象,解析日期字符串
        dateformat df = new simpledateformat("yyyy-mm-dd");
        /*
            调用parse()方法,解析日期字符串。
            当前方法上有一个编译时期的异常,针对于编译时期异常一定要进行处理。
            否则编译会报错。
          */
        date parse = df.parse(time);
        system.out.println("parse = " + parse);

        system.out.println("over");
    }
}

小结

异常分为

编译时期异常 : 顶层父类exception,编译时期检测,必须要处理的异常。

运行时期异常 : 顶层父类runtimeexception,运行时期检测,选择性处理的异常。一般不处理。

异常的处理

java异常处理的五个关键字:try、catch、finally、throw、throws

抛出异常throw

方法上经常要接收调用者传递的数据,而方法本身对于传递的数据通常会有范围的限定,超出范围即为不合法的数据。因此在程序开发时,通常需要对方法上传递的参数进行合法性的判断。如果传递的数据不合法,我们则需要将数据非法(异常)的具体信息告知给方法的调用者。就好像生活中看医生,如果身体出现了异常的现象,医生会告诉我们具体的病情一样的道理。

在java中如果需要将数据异常的信息告诉给方法的调用者知道,则需要使用throw关键字 。代码体现就是将异常信息进行封装,然后使用throw关键字抛出给调用者。

  • throw关键字:用来抛出一个异常对象,将这个异常对象传递给调用者,并结束当前方法的执行。步骤:
    1. 创建一个异常对象。封装异常的一些提示信息( 信息可以自己编写 )。
    2. 通过throw关键字,将这个封装异常信息的对象告知给调用者。

使用格式:

throw new 异常类名(参数);

例如:

throw new nullpointerexception("要访问的arr数组不存在");

throw new arrayindexoutofboundsexception("该索引在数组中不存在,已超出范围");

注意:异常在抛出时可以分为两种情况,即:抛出 编译时期异常 或者 运行时期异常。并且抛出的异常对象必须是异常体系所属的类。

学习完抛出异常的格式后,我们通过下面程序演示下throw的使用。

步骤

  1. 定义getelement()方法,传递int数组和下标。
  2. 使用if判断,传递的下标数据是否合法,如果不合法则抛出下标越界异常并提示异常信息。
  3. 实现功能,通过下标获取数组中下标对应的元素。
  4. 调用方法,查看结果。

实现

public class throwdemo {
    public static void main(string[] args) {
        //创建一个数组 
        int[] arr = {2,4,52,2};
        //根据索引找对应的元素 
        int index = 4;
        int element = getelement(arr, index);

        system.out.println(element);
        system.out.println("over");
    }
    /*
     * 根据 索引找到数组中对应的元素
     */
    public static int getelement( int[] arr,int index ){ 
        //判断  索引是否越界
        if( index < 0 || index > arr.length - 1 ) {
             /*
             判断条件如果满足,当执行完throw抛出异常对象后,方法已经无法继续运算。
             这时就会结束当前方法的执行,并将异常告知给调用者。这时就需要通过异常来解决。 
              */
             throw new arrayindexoutofboundsexception("哥们,下标越界了~~~");
        }
        int element = arr[index];
        return element;
    }
}

小结

程序中如果产生了问题,需要使用throw关键字,将描述问题的类即异常进行抛出,也就是将问题返回给该方法的调用者。 格式:

throw new 异常类("异常信息!");

使用throw关键字抛出的异常对象,必须是属于异常体系的类对象。

注意:throw语句下面,不能写其他语句,否则会因为无法被执行而导致程序编译报错。

那么对于调用者来说,该怎么处理呢?基于运行时期异常,一般是不处理。而针对于编译时期异常,一种是进行捕获处理,另一种就是继续将问题声明出去,使用throws声明处理。

objects非空判断

还记得我们学习过一个类objects吗,曾经提到过它由一些静态的实用方法组成,这些方法是null-save(空指针安全的)或null-tolerant(容忍空指针的),那么在它的源码中,将对象为null的值,进行了抛出异常操作。

  • public static t requirenonnull(t obj):查看指定引用对象不是null。

查看源码发现这里对为null的进行了抛出异常操作:

public static <t> t requirenonnull( t obj ) {
    if ( obj == null )
        throw new nullpointerexception();
    return obj;
}

步骤

  1. 定义getlength()方法,接收string类型数据,计算其长度并打印。
  2. 对传递的字符串数据进行合法性的判断,判断是否为空,如果为空则抛出空指针异常。
    • 先使用传统的if判断,然后使用object类中的requirenonnull()方法进行操作。
  3. 对比两种操作方式的区别。

实现

public static void getlength( string str ) {
    // if判断传递的字符串数据是否合法(为null)
    /*if( str == null ) {
              throw new nullpointerexception("字符串不能为null");
          }*/

    // objects静态方法requirenonnull()方法进行判断
    objects.requirenonnull( str ,"字符串不能为null");

    system.out.println(str + "长度为:" + str.length() );
}

小结

对传递的引用类型数据,一般都需要做控制针的判断。objects类中的requirenonnull()方法是专门用来判断引用类型的参数是否为空的。

声明异常 throws

throw关键字抛出的异常分为编译时期异常 和 运行时期异常。针对于运行时期的异常可以不用作任何的操作处理。但如果抛出的是编译时期的异常,则必须要进行处理。否则编译报错,程序无法运行。而对编译时期异常的处理方式主要分为: 异常声明 和 异常捕获。

  • 声明异常:将异常标识出来,报告给程序的使用者。让程序的使用者在程序的编译时期即可发现异常信息。
    • 例如生活中,超市售卖商品,有些商品快过期了,超市会在快过期的商品上贴上标签。让顾客在买商品时就能看到商品的异常信息。
  • throws关键字的作用就是在方法上进行异常的声明,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常( 继续抛出异常 )。

声明异常格式:

访问权限修饰符 返回值类型 方法名(参数) throws 异常类名1 , 异常类名2…{   }

注意:如果方法中抛出多个编译时期异常,也可以只声明多个异常的父类异常。

步骤

演示方法异常的声明。

  1. 定义read( string path )方法。
  2. 对传递path变量进行判断
    1. 判断是否为null,为null则抛出空指针异常。(运行异常)
    2. 判断path路径地址是否为"a.txt",如果不是则抛出filenotfoundexception文件不存在异常(编译异常)
    3. 判断path路径地址是否为"b.txt" , 如果不是则抛出ioexception异常对象(编译时期异常)
  3. 针对编译时期异常进行声明处理。
  4. 调用read()方法,并将main()方法被动接受到的异常继续声明到main()方法上。

实现

public class throwsdemo {
    public static void main(string[] args) throws filenotfoundexception, ioexception {
        read("a.txt");
    }

    public static void read(string path) throws filenotfoundexception, ioexception {
        if (!path.equals("a.txt")) {//如果不是 a.txt这个文件 
            // 我假设  如果不是 a.txt 认为 该文件不存在 是一个错误 也就是异常  throw
            throw new filenotfoundexception("文件不存在");
        }
        if (!path.equals("b.txt")) {
            throw new ioexception();
        }
    }
}

小结

如果通过throw关键字抛出的编译时期的异常,那么就必须要对异常进行处理 , 声明异常就是对编译时期异常的一种处理方式:将程序的调用者在编译时期就可以看到异常信息。需要使用throws关键字对异常进行声明:

访问权限修饰符 返回值类型 方法名(参数) throws 异常类名1, 异常类名2...{}

注意:

  1. throws关键字只能用在方法的声明处。
  2. throws声明的类必须是异常体系中的类。
  3. 如果方法中抛出多个编译时期异常,那么也必须在方法上继续声明抛出多个异常,或多个异常的父类异常。
  4. 哪个方法调用了声明异常的方法,那么当前方法就会被动接受被调用方法上的异常。

捕获异常try…catch

使用异常的声明时,如果方法中真的出了现异常现象,那么jvm就会将程序终止。造成的后果是后续的代码无法继续正常的执行。而如果希望即使出现了异常的现象,也能让后续的代码继续执行,可以使用异常的另外一种处理方式:捕获异常。

在java中使用:try-catch语句捕获异常。

  • 捕获异常:对异常语句,针对性进行捕获,捕获到异常信息后,可以对捕获的异常进行自定义方式的处理。
    • 提示:jvm对异常的默认处理方式就是终止程序的运行。
  • 捕获异常自定义处理的方式,throwable中的常用方法:
    • public void printstacktrace(): 打印异常的详细信息。
      包含了异常的类型,异常的原因,异常出现的位置,在开发和调试阶段,都得使用printstacktrace。
    • public string getmessage() : 获取发生异常的原因。提示给用户的时候,就提示错误原因。

捕获异常语法如下:

try{
     编写可能会出现异常的代码
} catch ( 异常类型 e ){
     处理异常的代码
     //记录日志/打印异常信息/继续抛出异常
}
/*
    try:该代码块中编写可能产生异常的代码。尝试运行程序。
    catch:用来捕获程序中产生的异常,并实现对捕获到的异常进行处理。
    异常类型 e:用来接收throw关键字抛出的异常对象(也就是异常的信息,因为异常对象中封装了异常的信息)
*/

注意:try 和 catch都不能单独使用,必须连用。

步骤

演示使用try-catch语句捕获异常。

  1. 定义read( string path )方法。
  2. 对传递path变量进行判断
  3. 判断path路径地址是否为"a.txt",如果不是则抛出filenotfoundexception文件不存在异常(编译异常)
  4. 针对编译时期异常使用try-catch语句进行捕获处理。
  5. 调用read()方法。

实现

public class trycatchdemo {
    public static void main(string[] args) {
        // 调用方法  如果方法是声明处理的异常,此处可以对方法进行捕获处理。
        read("b.txt");
        system.out.println("over");
    }
    // 演示捕获 异常
    public static void read(string path)  {
        //如果不是 a.txt这个文件
        if (!path.equals("a.txt")) {
            // 对异常进行捕获处理
            try {
                throw new filenotfoundexception("文件不存在");
            }catch (filenotfoundexception e ) {
                // 自定义处理异常,输出打印异常被捕获
                system.out.println("异常被抓住了!!!");
            }
        }
        // 打印传递的参数
        system.out.println("path = " + path );
    }
}

小结

针对于程序中的编译时期异常,除了声明处理之外,也可以使用捕获处理。

声明处理:遇到异常jvm会终止程序的运行。

捕获处理:遇到异常之后,可以自定义对异常处理。不用结束程序。

try{
  可能发生异常的代码;
}catch( 异常类型 e ) {
  对捕获的异常进行自定义的处理;
}
注意: try-catch 不能单独使用。

提示:如果方法上的异常是声明处理的,那么调用异常方法的方法就会被动接收到异常。此时可以使用声明的方式继续将异常声明出去,也可以使用try-catch语句进行捕获。

finally 代码块

在使用try-catch代码块处理异常时,有可能发生异常的代码是书写在try代码块中。而在异常代码的下面,有时还会有其他代码需要执行。但是一旦真有异常产生,程序会跳转到catch代码块中执行代码。那么异常代码后续的代码是无法执行的。而如果异常语句下面的代码无论是否有异常产生都需要执行,则可以使用finally代码块完成。

finally代码块:在finally代码块中存放的代码都是一定会被执行的。

当我们在try语句块中打开了一些物理资源(磁盘文件/网络连接/数据库连接等),我们都得在使用完之后,最终关闭打开的资源。

finally的语法:

try{
  有可能发生异常的代码;
} catch( 异常类型 e ) {
  自定义处理异常;
} finally {
  无论是否有异常产生,都需要执行的代码;
}

注意:finally不能单独使用。

我们之后学习的io流中,当打开了一个关联文件的资源,最后程序不管结果如何,都需要把这个资源关闭掉。

步骤

演示finally代码块。

  1. 定义read( string path )方法。
  2. 对传递path变量进行判断
  3. 判断path路径地址是否为"a.txt",如果不是则抛出filenotfoundexception文件不存在异常(编译异常)
  4. 针对编译时期异常使用throws进行声明处理。
  5. 调用read()方法,并捕获处理此方法。
  6. 在read()方法下面,写一个一定要执行的输出语句。
  7. 传递异常数据,产生异常。查看输出语句是否会被执行。
  8. 将一定要执行的输出语句书写到finally代码块中再次运行程序。查看结果。

实现

public class demo {
    public static void main(string[] args) {
        try {
            readfile("b.txt");
            // 无论是否有异常产生都需要执行的代码,写在finally代码块中
            //system.out.println("无论是否有异常产生我都需要执行...");
        } catch ( filenotfoundexception e ) {
            // 表示异常被抓住并且已经处理了
            system.out.println("异常被抓住了..");
            // 结束当前jvm,此时finally语句不会执行 
            // system.exit(0); // 开发中一般不会使用
        } finally {
            // 无论是否有异常产生都需要执行的代码,写在finally代码块中
            system.out.println("无论是否有异常产生我都需要执行...");
        }
    }
    // 演示finally代码块的使用
    public static void readfile ( string file ) throws filenotfoundexception {
       if( !file.equals("a.txt") ) { // 如果不是a.txt文件
           // 假设如果不是a.txt文件,则认为该文件不存在,抛出对应的异常
           throw new filenotfoundexception("文件不存在!");
       }
    }
}

小结

finally代码块是用来书写无论是否发生异常都需要执行的代码语句。只有在try或者catch中调用退出jvm的相关方法,此时finally才不会执行,否则finally永远会执行。

finally代码块注意事项

因为finally代码块中的代码一定会被执行,所以一般不会将需要返回结果的代码写在finally代码块中。因为会永远返回finally代码块中的结果。要尽量避免类似情况的发生。

步骤

  1. 定义geta()方法,返回int类型。
  2. 在方法内部定义变量 int a = 10;
  3. 定义try-catch-finally代码块
  4. 在try代码块中直接返回变量 a;
  5. 在finally代码块中给变量a重新赋值,返回在返回。
  6. 调用geta()方法。获取返回的结果并查看。

实现

public class demo {
    public static void main(string[] args) {
        // 调用方法,获取返回值
        int i = gata();
        system.out.println("i = " + i); // 100
    }
    // 演示捕获 异常
    public static int gata() {
        // 定义变量 a
        int a = 10;
        try{
            return a;
        }catch ( exception e ) {
            system.out.println(e);
        } finally {
            a = 100;
            return a;
        }
    }
}

小结

如果finally代码块中有return语句,那么一定会返回finally代码块中的结果。尽量避免类型情况的发生。

自定义异常

自定义异常类概述

在java中,一个异常类表示了一种异常现象。而这些异常类都jdk内部定义好的。但是实际开发中,也会出现很多异常现象,并且这些异常现象是jdk中没有定义的。此时我们可以根据自己业务的异常情况来自定义异常类。

  • 自定义异常类 : 在开发中根据自己业务的异常情况自定义的异常类。
  • 自定义异常类注意事项 :
    • java中规定,只有throwable异常体系的类,才能进行抛出或声明等异常处理。
      • 所以自定义的异常类必须继承异常类体系。
    • 自定义一个编译期异常:自定义类 并继承于java.lang.exception。
    • 自定义一个运行时期的异常类:自定义类 并继承于java.lang.runtimeexception。

自定义异常类格式

访问权限修饰符 class 异常类名 extends exception | runtimeexception {
  // 空参构造
  public 异常类名(){}
  // 异常信息提示构造  使用字符串数据提示异常的具体信息
  public 异常类名( string message ){
    super( message );
  }
}

步骤

定义一个注册异常的编译时期异常类。

  1. 自定义loginexception类。
  2. 继承exception类。
  3. 在类中定义空参构造 和 异常信息提示构造。

实现

// 业务逻辑异常
public class loginexception extends exception {
    /**
     * 空参构造
     */
    public loginexception() {
    }

    /**
     *
     * @param message 表示异常提示
     */
    public loginexception(string message) {
        super(message);
    }
}

小结

当程序中出现异常现象时,我们需要将异常信息封装,然后抛出给程序的调用者知道。代码体现就是创建异常现象对应的异常类对象,然后使用throw关键字抛出。而如果程序中的异常现象没有对应的异常类时,我们可以根据项目情况自己定义异常类。而java中规定,只有属于异常体系的类才能使用处理异常的关键字进行处理。所以自定义的异常类要继承异常体系类。

如果希望是编译时期异常则继承:exception类。

如果希望是运行时期异常则继承:runtimeexception类。

自定义的异常类中需要提供一个空参构造,一个异常信息提示的构造方法。

自定义异常的练习

步骤

要求:我们模拟登陆操作,如果用户名已存在,则抛出异常并提示:亲,该用户名已经被注册。

  1. 定义一个静态的成员字符串数组,并在数组中声明几个账号,用于模拟数据库。
  2. 定义checkusername( string name )方法,判断注册的账号是否存在
  3. 遍历取出模拟数据库数组中的数据
  4. 使用数据库中已经存在的账号和注册的账号进行比较。如果用户名已存在,则抛出异常并提示:亲,该用户名已经被注册。

实现

public class demo {
    // 模拟数据库已经存在的账号
    private static string[] names = {"zhangsan","lisi","wangwu"};

    public static void main(string[] args) {
        // 调用方法
        try{
            // 可能出现异常的代码
            checkusername("lisi");
            // 没有发生异常,则表示注册成功
            system.out.println("账号注册成功!!");
        }catch ( loginexception e ) {
            // 处理异常
            e.printstacktrace();
        }
    }

    // 判断当前账号是否存在
    public static boolean checkusername ( string unams ) throws loginexception {
        // 循环数据库中的所有账号
        for( string name : names ) {
            // 将取出的数据库中的账号和申请的账号比价
            if( unams.equals( name ) ) {
                // 如果进入if说明账号已经存在,则抛出账号存在异常
                throw new loginexception("账号已经存在!!");
            }
        }
        // 没有抛出异常,说明账号不存在。
        return true;
    }
}

小结

自定义异常类和jdk中定义好的异常类的使用方式都是一样的。也可以通过throw关键字抛出,通过throws关键字声明,或者通过try-catch代码块进行捕获处理。

3.3 多个异常捕获扩展

在程序中,异常现象不可能只出现一个。有时一个程序中会出现多个异常现象。多个异常的捕获,有多种不同的方式。

多个异常多次捕获多次处理

步骤

  1. 自定义异常a类,继承exception类。
  2. 自定义异常b类,继承继承a类。
  3. 定义getaexception( int a )方法,并对a进行判断,如果a==0,则抛出a异常。
  4. 定义getbexception( int b )方法,并对b进行判断,如果b==0,则抛出b异常。
  5. 调用getaexception( int a ),并使用捕获处理。
  6. 调用getbexception( int b ),并使用捕获处理。

实现

// 自定义异常a类
public class a extends runtimeexception {
    // 空参构造
    public a() { }

    // 异常提示构造
    public a(string message) {
        super(message);
    }
}

// 自定义异常b类,继承a类
public class b extends a {
    // 空参构造
    public b() {}

    // 异常提示构造
    public b(string message) {
        super(message);
    }
}

// 演示多个异常的单独处理
public class demo {
    public static void main(string[] args) {
        // 单独处理a异常
        try{
            getaexception(0);
        }catch ( a e ) {
            system.out.println("异常被抓住了...");
            e.printstacktrace();
        }

        // 单路处理b异常
        try {
            getbexception(0);
        } catch ( b e ) {
            system.out.println("异常被抓住了...");
            e.printstacktrace();
        }

        /*
            针对于运行时期异常,使用try-catch的方式进行捕获。
            好处在于: 即使有异常发生,后续代码也可以继续执行。
        */
        system.out.println("后续代码....");
    }

    // 定义方法,抛出a类异常
    public static void getaexception( int a ) {
        if( a == 0 ) {
            throw new a("不能为0!");
        }
    }
    // 定义方法,抛出b类异常
    public static void getbexception( int b ) {
        if( b == 0 ) {
            throw new b("不能为0!");
        }
    }
}

小结

当程序中有多个异常时,基于需求的需要我们可以对多个异常分别使用try-catch语句进行捕获处理。

多个异常一次捕获多次处理

try-catch代码块扩展语法:

try{
     编写可能会出现异常的代码
}catch( 异常类型a  e ){  //当try中出现a类型异常,就用该catch来捕获.
     处理异常的代码
     //记录日志/打印异常信息/继续抛出异常
}catch( 异常类型b  e ){  //当try中出现b类型异常,就用该catch来捕获.
     处理异常的代码
     //记录日志/打印异常信息/继续抛出异常
}

步骤

  1. 调用getaexception( int a )
  2. 调用getbexception( int b )
  3. 对两个异常方法一次进行捕获
  4. 使用多个catch代码块处理捕获的多个异常

实现

// 演示多个异常的一次捕获,多次处理
public class demo {
    public static void main(string[] args) {
        // 多个异常一次捕获,多次处理
        try{
            getaexception(0);
            getbexception(0);
        }catch ( b e ) {
            system.out.println("b类异常被抓住了...");
            e.printstacktrace();
        }catch ( a e ) {
            system.out.println("a类异常被抓住了...");
            e.printstacktrace();
        }
    }
    // 定义方法,抛出a类异常
    public static void getaexception( int a ) {
        if( a == 0 ) {
            throw new a("不能为0!");
        }
    }
    // 定义方法,抛出b类异常
    public static void getbexception( int b ) {
        if( b == 0 ) {
            throw new b("不能为0!");
        }
    }
}

小结

当程序中有多个异常时,基于需求的需要我们可以对多个异常使用try代码块一次捕获,然后使用多个catch语句分别对异常进行处理。

注意:这种异常处理方式,要求多个catch中的异常不能相同,并且若catch中的多个异常之间有子父类异常的关系,那么子类异常要求在上面的catch处理,父类异常在下面的catch处理。

多个异常一次捕获一次处理

步骤

  1. 调用getaexception( int a )
  2. 调用getbexception( int b )
  3. 对两个异常方法一次进行捕获
  4. 使用一个catch代码块处理捕获的多个异常

实现

// 演示多个异常的一次捕获,一次处理
public class demo {
    public static void main(string[] args) {
        // 多个异常一次捕获,一次处理
        try{
            getaexception(1);
            getbexception(0);
        }catch ( a e ) {
            system.out.println("类异常被抓住了...");
            e.printstacktrace();
        }
    }
    // 定义方法,抛出a类异常
    public static void getaexception( int a ) {
        if( a == 0 ) {
            throw new a("a不能为0!");
        }
    }
    // 定义方法,抛出b类异常
    public static void getbexception( int b ) {
        if( b == 0 ) {
            throw new b("b不能为0!");
        }
    }
}

小结

当程序中有多个异常时,基于需求的需要我们可以对多个异常使用try代码块一次捕获,然后使用一个catch语句对异常进行处理。

注意:这种异常处理方式,要不catch语句中的异常类型,必须是多个异常的父类类型。能够接收任意一个被抛出的异常对象。

继承中异常注意事项

  • 如果父类声明了多个异常,子类重写父类方法时,只能声明相同的异常或者是他的子集。也可以不声明
  • 父类方法没有声明异常,子类重写父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出

步骤

  1. 创建父类,在类中定义show( int a , int b )方法.
  2. 分别对变量 a 和 b进行判断,如果结果为0,则分别抛出a,b异常。
  3. 定义子类,重写父类中的方法。验证继承中的异常注意事项。

实现

// 父类
class fu {
    // 父类中的方法
    public void show( int a, int b ) throws a, b {
        if( a == 0 ) {
            throw new a("a不能为0!");
        }
        if( b == 0 ) {
            throw new b("b不能为0!");
        }
    }
}
class zi extends fu {
    // 子类重写父类中的方法
    public void show( int a , int b ) throws b {
        system.out.println("重写....");
    }
}

小结

继承中,子类重写父类方法时,父类没有声明异常。子类也不能声明异常。如果父类上有声明异常,子类重写时可以不用声明,或者声明父类异常上的子类异常,但是异常的个数不能超过父类声明的异常个数。

健康的父亲,儿子也应该健康。多病的父亲,基于进化学,儿子应该比父亲健康。