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("重写....");
}
}
小结
继承中,子类重写父类方法时,父类没有声明异常。子类也不能声明异常。如果父类上有声明异常,子类重写时可以不用声明,或者声明父类异常上的子类异常,但是异常的个数不能超过父类声明的异常个数。
健康的父亲,儿子也应该健康。多病的父亲,基于进化学,儿子应该比父亲健康。
标签:throw,int,public,处理,catch,JavaSE,解析,异常,抛光 来源: https://www.cnblogs.com/ownmg/p/10707592.html