JavaSE 异常抛光解析
异常
异常指的是程序中的不正常现象,一般异常都是由第三方数据的使用造成的。java中每种异常现象都会有一个对应的异常类。java对异常的处理方式就是终止程序。异常机制其实是为了帮助我们找到程序中的问题。异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行。
异常体系
java将程序中遇到的每一种异常现象都封装成一个对应的异常类。然后将众多的异常抽取成一个异常体系。而整个异常系统又分为: 错误 和 异常两种现象。
- java.lang.throwable:异常体系的顶层父类。其下有两个子类:
- java.lang.error: 错误体系的顶层父类。严重的错误error,无法处理,只能预先避免,好比绝症。
- 比如开辟数组空间的个数过多,导致内存不够使用。这不是代码的问题,而是硬件不足造成的。
- java.lang.exception:异常体系中的顶层父类。程序中的异常就是指java.lang.exception。
- 程序中一旦产生了异常的现象,程序开发人员可以通过代码纠正(就好比生活中身体出现异常,可以通过药物或其他方式进行治疗)。异常是必须要处理的(好比发烧、感冒、阑尾炎)。
小结
throwable是异常体系的根类。针对于程序中的异常,分为:错误(error)和异常(exception)。
error:无法处理,尽量避免。
exception:必须处理。
异常的产生过程解析
当我们操作了数组不存在的下标时,程序会产生一个数组索引越界异常arrayindexofboundsexception。我们通过图解来解析下异常产生的过程。
步骤
- 创建一个数组的工具类,类中定义静态方法getelement(),通过提供的数组和下标获取对应的元素。
- 创建测试类,在类中定义数组,开辟空间个数3。
- 通过数组工具类名调用获取数组元素的方法,并传递创建的数组和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"); } }
上述程序执行过程图解:
小结
当程序中的数据产生异常之后,jvm会识别当前异常。然后将异常的信息进行封装,抛给程序的调用者,让调用者基于获取的异常信息进行处理。而如果没有对异常进行处理,则异常最后会由jvm进行处理。jvm处理的方式就是终止程序,并将异常的信息打印到控制台。
异常分类和处理
目标
程序中需要开发人员处理的异常指的是exception,这类异常一旦出现,我们就要对代码进行更正,修复程序。
异常(exception)的分类:分为 编译时期异常 和 运行时期异常。
- 编译时期异常:在编译时期,就会检查。如果没有处理异常,则编译失败。( 如日期格式化异常 )
- exception :编译时期异常顶层父类。除特殊的子类外,其下所有子类都属于编译时期异常类。
- 运行时期异常:在运行时期,检查异常。运行中发现异常则程序停止运行。编译时期,不会被编译器检测。
- runtimeexception :exception的一个特殊子类,运行时期异常顶层父类。其下的所有子类都属于运行时期的异常类。如:下标越界。
- 异常的处理
- 编译时期异常:编译时就会编译报错,因此必需要处理。只有处理之后才能编译成功,产生class文件。然后才能够让程序运行。
- 运行时期异常:编译时期不会检查,运行时期检测。如果运行时真的出现了异常现象jvm会结束程序。针对于运行时期异常:可以处理,也可以不用处理,一般不处理。
步骤
- 在演示异常的类中创建意思日期字符串。
- 创建dateformat对象,并调用parse()方法解析日期字符串(编译异常)
- 对比分析编译时期和运行时期异常类。
实现
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关键字:用来抛出一个异常对象,将这个异常对象传递给调用者,并结束当前方法的执行。步骤:
- 创建一个异常对象。封装异常的一些提示信息( 信息可以自己编写 )。
- 通过throw关键字,将这个封装异常信息的对象告知给调用者。
使用格式:
throw new 异常类名(参数);
例如:
throw new nullpointerexception("要访问的arr数组不存在"); throw new arrayindexoutofboundsexception("该索引在数组中不存在,已超出范围");
注意:异常在抛出时可以分为两种情况,即:抛出 编译时期异常 或者 运行时期异常。并且抛出的异常对象必须是异常体系所属的类。
学习完抛出异常的格式后,我们通过下面程序演示下throw的使用。
步骤
- 定义getelement()方法,传递int数组和下标。
- 使用if判断,传递的下标数据是否合法,如果不合法则抛出下标越界异常并提示异常信息。
- 实现功能,通过下标获取数组中下标对应的元素。
- 调用方法,查看结果。
实现
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; }
步骤
- 定义getlength()方法,接收string类型数据,计算其长度并打印。
- 对传递的字符串数据进行合法性的判断,判断是否为空,如果为空则抛出空指针异常。
- 先使用传统的if判断,然后使用object类中的requirenonnull()方法进行操作。
- 对比两种操作方式的区别。
实现
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…{ } 注意:如果方法中抛出多个编译时期异常,也可以只声明多个异常的父类异常。
步骤
演示方法异常的声明。
- 定义read( string path )方法。
- 对传递path变量进行判断
- 判断是否为null,为null则抛出空指针异常。(运行异常)
- 判断path路径地址是否为"a.txt",如果不是则抛出filenotfoundexception文件不存在异常(编译异常)
- 判断path路径地址是否为"b.txt" , 如果不是则抛出ioexception异常对象(编译时期异常)
- 针对编译时期异常进行声明处理。
- 调用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...{}
注意:
- throws关键字只能用在方法的声明处。
- throws声明的类必须是异常体系中的类。
- 如果方法中抛出多个编译时期异常,那么也必须在方法上继续声明抛出多个异常,或多个异常的父类异常。
- 哪个方法调用了声明异常的方法,那么当前方法就会被动接受被调用方法上的异常。
捕获异常try…catch
使用异常的声明时,如果方法中真的出了现异常现象,那么jvm就会将程序终止。造成的后果是后续的代码无法继续正常的执行。而如果希望即使出现了异常的现象,也能让后续的代码继续执行,可以使用异常的另外一种处理方式:捕获异常。
在java中使用:try-catch语句捕获异常。
- 捕获异常:对异常语句,针对性进行捕获,捕获到异常信息后,可以对捕获的异常进行自定义方式的处理。
- 提示:jvm对异常的默认处理方式就是终止程序的运行。
- 捕获异常自定义处理的方式,throwable中的常用方法:
- public void printstacktrace(): 打印异常的详细信息。
包含了异常的类型,异常的原因,异常出现的位置,在开发和调试阶段,都得使用printstacktrace。 - public string getmessage() : 获取发生异常的原因。提示给用户的时候,就提示错误原因。
- public void printstacktrace(): 打印异常的详细信息。
捕获异常语法如下:
try{ 编写可能会出现异常的代码 } catch ( 异常类型 e ){ 处理异常的代码 //记录日志/打印异常信息/继续抛出异常 } /* try:该代码块中编写可能产生异常的代码。尝试运行程序。 catch:用来捕获程序中产生的异常,并实现对捕获到的异常进行处理。 异常类型 e:用来接收throw关键字抛出的异常对象(也就是异常的信息,因为异常对象中封装了异常的信息) */
注意:try 和 catch都不能单独使用,必须连用。
步骤
演示使用try-catch语句捕获异常。
- 定义read( string path )方法。
- 对传递path变量进行判断
- 判断path路径地址是否为"a.txt",如果不是则抛出filenotfoundexception文件不存在异常(编译异常)
- 针对编译时期异常使用try-catch语句进行捕获处理。
- 调用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代码块。
- 定义read( string path )方法。
- 对传递path变量进行判断
- 判断path路径地址是否为"a.txt",如果不是则抛出filenotfoundexception文件不存在异常(编译异常)
- 针对编译时期异常使用throws进行声明处理。
- 调用read()方法,并捕获处理此方法。
- 在read()方法下面,写一个一定要执行的输出语句。
- 传递异常数据,产生异常。查看输出语句是否会被执行。
- 将一定要执行的输出语句书写到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代码块中的结果。要尽量避免类似情况的发生。
步骤
- 定义geta()方法,返回int类型。
- 在方法内部定义变量 int a = 10;
- 定义try-catch-finally代码块
- 在try代码块中直接返回变量 a;
- 在finally代码块中给变量a重新赋值,返回在返回。
- 调用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。
- java中规定,只有throwable异常体系的类,才能进行抛出或声明等异常处理。
自定义异常类格式
访问权限修饰符 class 异常类名 extends exception | runtimeexception { // 空参构造 public 异常类名(){} // 异常信息提示构造 使用字符串数据提示异常的具体信息 public 异常类名( string message ){ super( message ); } }
步骤
定义一个注册异常的编译时期异常类。
- 自定义loginexception类。
- 继承exception类。
- 在类中定义空参构造 和 异常信息提示构造。
实现
// 业务逻辑异常 public class loginexception extends exception { /** * 空参构造 */ public loginexception() { } /** * * @param message 表示异常提示 */ public loginexception(string message) { super(message); } }
小结
当程序中出现异常现象时,我们需要将异常信息封装,然后抛出给程序的调用者知道。代码体现就是创建异常现象对应的异常类对象,然后使用throw关键字抛出。而如果程序中的异常现象没有对应的异常类时,我们可以根据项目情况自己定义异常类。而java中规定,只有属于异常体系的类才能使用处理异常的关键字进行处理。所以自定义的异常类要继承异常体系类。
如果希望是编译时期异常则继承:exception类。
如果希望是运行时期异常则继承:runtimeexception类。
自定义的异常类中需要提供一个空参构造,一个异常信息提示的构造方法。
自定义异常的练习
步骤
要求:我们模拟登陆操作,如果用户名已存在,则抛出异常并提示:亲,该用户名已经被注册。
- 定义一个静态的成员字符串数组,并在数组中声明几个账号,用于模拟数据库。
- 定义checkusername( string name )方法,判断注册的账号是否存在
- 遍历取出模拟数据库数组中的数据
- 使用数据库中已经存在的账号和注册的账号进行比较。如果用户名已存在,则抛出异常并提示:亲,该用户名已经被注册。
实现
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 多个异常捕获扩展
在程序中,异常现象不可能只出现一个。有时一个程序中会出现多个异常现象。多个异常的捕获,有多种不同的方式。
多个异常多次捕获多次处理
步骤
- 自定义异常a类,继承exception类。
- 自定义异常b类,继承继承a类。
- 定义getaexception( int a )方法,并对a进行判断,如果a==0,则抛出a异常。
- 定义getbexception( int b )方法,并对b进行判断,如果b==0,则抛出b异常。
- 调用getaexception( int a ),并使用捕获处理。
- 调用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来捕获. 处理异常的代码 //记录日志/打印异常信息/继续抛出异常 }
步骤
- 调用getaexception( int a )
- 调用getbexception( int b )
- 对两个异常方法一次进行捕获
- 使用多个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处理。
多个异常一次捕获一次处理
步骤
- 调用getaexception( int a )
- 调用getbexception( int b )
- 对两个异常方法一次进行捕获
- 使用一个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语句中的异常类型,必须是多个异常的父类类型。能够接收任意一个被抛出的异常对象。
继承中异常注意事项
- 如果父类声明了多个异常,子类重写父类方法时,只能声明相同的异常或者是他的子集。也可以不声明
- 父类方法没有声明异常,子类重写父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出
步骤
- 创建父类,在类中定义show( int a , int b )方法.
- 分别对变量 a 和 b进行判断,如果结果为0,则分别抛出a,b异常。
- 定义子类,重写父类中的方法。验证继承中的异常注意事项。
实现
// 父类 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("重写...."); } }
小结
继承中,子类重写父类方法时,父类没有声明异常。子类也不能声明异常。如果父类上有声明异常,子类重写时可以不用声明,或者声明父类异常上的子类异常,但是异常的个数不能超过父类声明的异常个数。
健康的父亲,儿子也应该健康。多病的父亲,基于进化学,儿子应该比父亲健康。
下一篇: PHP爆绝对路径方法收集整理
推荐阅读
-
解析PHP中intval()等int转换时的意外异常情况
-
Node.js 异步异常的处理与domain模块解析
-
scrapy urllib.parse 解析含有'/'字符ftp链接时异常的临时处理
-
SpringBoot 2 统一异常处理过程解析
-
Gson解析空字符串异常的处理
-
【JAVASE】异常(10)
-
解析C#中断言与异常的应用方式及异常处理的流程控制
-
Python异常对代码运行性能的影响实例解析
-
Java进阶篇5_SpringMVC的简介、SpringMVC的组件解析、SpringMVC的数据响应、SpringMVC获取请求数据、SpringMVC拦截器、SpringMVC异常处理机制
-
Dom4J解析使用xpath java.lang.NoClassDefFoundError: org/jaxen/JaxenException异常