java 异常进阶 多异常和自定义异常详解

简介: java 多异常,子父类异常,自定义异常详解。

目录

一、前言:

二、多异常的处理:

       Δ前言:

       1.处理方式一:

               代码演示:

       2.处理方式二:

               代码演示:

       3.处理方式三:

               代码演示:

三、PS:finally代码块中存在return的问题:

       代码演示:

四、子父类异常:

       1.子父类异常的关系:

       2.代码演示①:

       3.代码演示②:

五、自定义异常:

       1.介绍:

       2.格式:

       3.注意事项:

       4.代码演示:

               ①自定义异常类:

               ②测试自定义异常:

六、完结撒❀:


一、前言:

       大家好,这篇博客是对java异常基础篇的一个内容延申和补充,主要和大家分享一下多异常的三种处理方式自定义异常介绍自定义异常的定义和使用等等,感谢阅读。              

二、多异常的处理:

       Δ前言:

       多异常,即代码中出现了多个异常

       多异常的处理方式:

        1.分别捕获,并分别处理

        2.一次捕获,但多次处理

        3.一次捕获,且一次处理

       1.处理方式一:

       1.分别捕获,并分别处理

       我们首先来看一下以下代码段:

int[] array= {1, 2, 11, 985, 5};
System.out.println("我想访问数组索引为5的元素:"+array[5]);

image.gif

       显然,直接运行上述代码,会报异常ArrayIndexOutOfBoundsException(数组下标越界异常)。我们再来看看另一代码段:

inti=10/0;
System.out.println("The value of i is : "+i);

image.gif

       显然,直接运行这段代码会报异常ArithmeticException(运算中的异常)。

       so,up就以这两个异常为栗,给大家演示以下多异常的处理。    

               代码演示:

packageknowledge.exception.advance;
publicclassMultipleAnomaly {
publicstaticvoidmain(String[] args) {
/*利用try...catch捕获*///1.分别捕获,并分别处理try {
int[] array= {1, 2, 11, 985, 5};
System.out.println("我想访问数组索引为5的元素:"+array[5]);
        } catch (ArrayIndexOutOfBoundsExceptionarrayIndexE) {
System.out.println(arrayIndexE);
        }
try {
inti=10/0;
System.out.println("The value of i is :"+i);
        } catch (ArithmeticExceptionariE) {
System.out.println(ariE);
        }
    }
}

image.gif

               运行结果:

image.png

       2.处理方式二:

       2.一次捕获,但多次处理

      实现方式一个try,多个catch

       Δ注意事项 :

      catch语句里面定义的异常变量,如果存在子父类关系,那么子类的异常变量必须定义在父类异常变量的上面,否则就会报错。 eg : 下面代码段:

try {
inti=10/0; 
int[] array= {1, 2, 11, 985, 5};
System.out.println("我想访问数组索引为5的元素:"+array[5]);
} catch (Exceptione) {
System.out.println(e);
} catch (ArrayIndexOutOfBoundsExceptionarrayIndexE) {
System.out.println(arrayIndexE);
}

image.gif

       报错情况如下图所示

image.png

       正如IDEA所说的,该异常已经被捕获了。        

      报错原因:

       try中如果出现了异常对象,会把异常对象抛出给catch处理,抛出的异常对象, 会从上至下依次赋值给catch中定义的变量。 如果是子类变量在前,父类变量在后(即正常情况下),因为父类异常对象本身就无法赋值给子类异常对象, 因此try会自动跳开,最终子类异常对象赋值给子类异常变量,父类异常对象赋值给父类异常变量;

        但是,

        如果是父类变量在前,子类变量在后,因为子类异常对象本身是可以赋值给父类异常对象的, 就是多态嘛。因此try不会跳开,而是将子类异常对象也赋值给了父类异常变量,这就导致 下面定义子类异常变量的catch语句是多余的语句,因此报错。

               代码演示:

packageknowledge.exception.advance;
publicclassMultipleAnomaly {
publicstaticvoidmain(String[] args) {
//2.一次捕获,但多次处理try {
inti=10/0; //直接运行这段代码会报异常ArithmeticExceptionint[] array= {1, 2, 11, 985, 5};
System.out.println("我想访问数组索引为5的元素:"+array[5]);
        } catch (ArithmeticExceptionariE) {
System.out.println(ariE);
        } catch (ArrayIndexOutOfBoundsExceptionarrayIndexE) {
System.out.println(arrayIndexE);
        }
System.out.println("---------------------------------");
/*try中若出现异常,会立刻跳转至catch,此处当执行到int i = 10 / 0; 时,就会跳转至catch语句,因此控制台只会打印出ArithmeticException*/    }
}

image.gif

               运行结果

              image.png

       3.处理方式三:

       3.一次捕获,且一次处理

       刚刚我们讲到了为什么多个catch语句中子类异常变量必须定义在父类异常变量的前面。其实,一次捕获一次处理,也是应用了这个原理。怎么做到一次处理?直接给它定义一个父类异常的异常变量不就完了么。

       直接定义一个父类异常变量,那么try无论是父类本身的异常对象抛给catch,还是它的子类对象抛给catch ,父类异常变量都可以做接收,一劳永逸!      

               代码演示:

packageknowledge.exception.advance;
publicclassMultipleAnomaly {
publicstaticvoidmain(String[] args) {
//3.一次捕获,且一次处理try {
int[] array= {1, 2, 11, 985, 5};
System.out.println("我想访问数组索引为5的元素:"+array[5]);
inti=10/0; 
        } catch (Exceptione) {
System.out.println(e);
        }
/*直接定义异常类父类Exception,可以接收绝大多数的异常对象。*/    }
}

image.gif

               运行结果:        

image.png

               注意,这里我们先产生了数组下标越界异常(ArrayIndexOutOfBoundsException),立刻便跳转到catch语句,因此控制台只打印出了ArrayIndexOutOfBoundsException。

三、PS:finally代码块中存在return的问题:

      如果finally中含有return语句,会永远只返回finally中return的结果 因此要避免此情况发生。

       PS : 注意!

       ①若finally代码块之前的catch语句中也有return语句,那么该return语句中的内容也会执行!(eg : return ++i; )。只不过执行后并不会由当前return语句返回,而是在底层用一个临时变量temp保存了该返回值,最终的返回值仍是以finally代码块中的return语句为准。若finally代码块中无return语句,才会返回去执行之前的return语句,最终返回temp变量保存的值。

       ②有时会出现try-finally的搭配,这种用法相当于没有捕获异常,因此若出现异常程序会直接崩掉。适用于“执行一段代码,不管有没有出现异常都要执行某个业务逻辑”的场景。

       代码演示:

packageknowledge.exception.advance;
/*如果finally中含有return语句,会永远返回finally中的结果因此要避免此情况发生。*/publicclassFinallyReturn {
publicstaticvoidmain(String[] args) {
intnumber=getNumber();
System.out.println("The value of number is : "+number);
    }
publicstaticintgetNumber() {
inti=11;
try {
returni;
        } catch (Exceptione) {
System.out.println(e);
        } finally {
i=5;
returni;
        }
    }
}
//最终的返回值是5

image.gif

               运行结果

image.png

四、子父类异常:

       1.子父类异常的关系:

               关于子父类的异常:

                ①如果父类中抛出多个异常,子类重写父类方法时, 抛出和父类相同的异常,或者是父类异常的子类,或者不抛出

               ②如果父类中没有抛出异常,子类重写父类该方法时, 也不可抛出异常。此时子类若产生了异常,只能做捕获处理,不能声明抛出

               人话:

                只要子类和父类保持一致,就不会出事儿。

       2.代码演示①:

       由于代码中的方法涉及到了读取文本文件,up先给大家看一下文本文件1.txt中内容,如下:

     image.png

       我们以Father1类作为第一个演示类,Father1类代码如下:

packageknowledge.exception.advance;
importjava.io.*;
publicclassFather {
publicvoidreadText() throwsIOException {
Readerreader=newFileReader("D:\\JAVA\\IDEA\\file\\1.txt");
intdata;
while ((data=reader.read()) !=-1) {
System.out.println((char)data);
        }
reader.close();
    }
publicvoidreadFile() throwsIOException {
thrownewIOException("😋抛出一个IO父类异常对象");
    }
publicvoidgetElement() throwsIndexOutOfBoundsException {
System.out.println("这是父类的方法");
    }
}
classSonextendsFather{
//1.父类抛出异常时@Override//1_①抛出和父类相同的异常publicvoidreadText() throwsIOException {
Readerreader=newFileReader("D:\\JAVA\\IDEA\\file\\1.txt");
char[] charArray=newchar[1024];  //用于读写数据的字符数组的长度最好是1024的整数倍intdata;
while ((data=reader.read(charArray)) !=-1) {
System.out.println(charArray);
        }
reader.close();
    }
//1_②抛出父类异常的子类@OverridepublicvoidreadFile() throwsFileNotFoundException {
thrownewFileNotFoundException();
    }
//1_③不抛出异常@OverridepublicvoidgetElement() {
System.out.println("这是子类的方法");
    }
}
classTest1 {
publicstaticvoidmain(String[] args) throwsIOException {
Fatherf=newFather();
Sons=newSon();
f.readText();
System.out.println("-----------------------------------");
s.readText();
f.readFile();
f.getElement();
s.readFile();
s.getElement();
    }
}

image.gif

              运行效果(GIF图):

image.png

       3.代码演示②:

       up以Father2类作为第二个演示类,来演示如果父类没有抛出异常的情况下,子类的处理情况。Father2代码如下:

packageknowledge.exception.advance;
publicclassFather2 {
publicvoidf() {
System.out.println("父类没有抛出任何异常。");
    }
}
classSon2extendsFather2 {
//2.父类没有抛出异常时@Override//    public void f() throws Exception{                 //如果此时子类声明异常,编辑器会报错。//        System.out.println("此时子类也不能抛出任何异常");//    }publicvoidf() {
System.out.println("此时子类也不能抛出任何异常");
System.out.println("假设子类重写方法时产生了异常,也只能捕获处理,不可以抛出异常对象!");
try {
thrownewException("无聊抛出一个异常对象玩玩儿😁");
        } catch (Exceptione) {
e.printStackTrace();    //这个方法在异常基础篇分享过        }
    }
}
classTest2 {
publicstaticvoidmain(String[] args) {
Father2ff=newFather2();
Son2ss=newSon2();
ff.f();
System.out.println("--------------------------------------");
ss.f();
    }
}

image.gif

               运行效果

image.png

五、自定义异常:

       1.介绍:

       java中本身已经定义了许多的异常类,但是某些情况下仍然不够我们霍霍的,所以需要我们自己去定义一些异常类。

       2.格式:

      public class ___Exception extends Exception / RuntimeException {

               //自定义的异常类内部,需要定义两个构造方法

               //一个空参构造

               //一个带参构造(说明异常信息)

       }

       3.注意事项:

       ①自定义异常类的类名一般都是以"Exception"作为结尾,以达到见名知意的效果,表示该类是一个异常类

       ②自定义的异常类,必须得继承Exception类或者RuntimeException类

       继承Exception类,表示自定义的异常类是一个编译期异常

       继承RuntimeException类,表示自定义的异常类是一个运行期异常;      

       关于编译期异常和运行期异常区别以及处理方式,我们在java异常基础篇已经讲过,此处不再赘述。

       4.代码演示:

               ①自定义异常类:

               我们创建一个RegisterException类的自定义异常类,当我们模拟注册用户时,如果用户输入的用户名异常,则可以抛出RegisterException类的异常对象。

               RegisterException类代码如下:

packageknowledge.exception.advance;
publicclassRegisterExceptionextendsException {
//1.添加一个空参构造publicRegisterException() {
super();    //默认调用父类的空参构造    }
//2.添加一个带参构造(说明异常信息)/*查看源码发现(IDEA快捷键Ctrl + b可查看类的源码),所有的异常类都会有一个带异常信息的构造方法,让父类来处理这个异常信息。*/publicRegisterException(Stringmessage) {
super(message);
    }
}

image.gif

               ②测试自定义异常:

               有了自定义的异常类,接着我们就可以创建一个测试类来测试自定义异常类,这里我们以TestRegisterException类作为演示类,需求 :模拟注册用户的操作,如果用户名已经存在,则抛出RegisterException异常并提示用户: 这个用户名已经注册过了哈

               TestRegisterException类代码如下:                

packageknowledge.exception.advance;
importjava.util.Scanner;
/*requirement : 模拟注册用户的操作,如果用户名已经存在,则抛出RegisterException异常并提示用户:这个用户名已经注册过了哈。mentality(思路) :1.首先,可以使用一个数组来保存已注册的用户名,模拟数据库。2.其次,可以使用Scanner类获取用户想注册的用户名,模拟前端页面。3.定义一个方法,对用户输入的用户名进行判断。若已存在该用户名,抛出RegisterException异常并提示用户:这个用户名已经注册过了哈。若不存在该用户名,提示用户:注册成功🌶!*/publicclassTestRegisterException {
publicstaticvoidmain(String[] args) throwsRegisterException {
//1.首先,可以使用一个数组来保存已注册的用户名,模拟数据库。String[] names= {"大伟哥", "赵鑫鑫", "杜兰特", "Cyan", "王五"};
//2.其次,可以使用Scanner类获取用户想注册的用户名,模拟前端页面。Scannersc=newScanner(System.in);
System.out.println("请输入你想注册的用户名:");
StringuserName=sc.nextLine();
ifExist(names, userName);
sc.close();
    }
//3.定义一个方法,对用户输入的用户名进行判断。publicstaticvoidifExist(String[] names, StringuserName) throwsRegisterException {
inttemp=0;
for (Stringname : names) {
if (name.equals(userName)) {
temp=-1;
thrownewRegisterException("这个用户名已经注册过了哈。");
            }
        }
if (temp==0) {
System.out.println("注册成功🌶!");
        }
/*加入这个判断条件更严谨,以不会导致在抛出异常对象后仍然打印出"注册成功🌶!"的提示信息。其实还有多种处理方式,比如在抛出异常对象后执行return语句,直接结束方法体,都可以。*/    }
}

image.gif

               运行效果如下GIF图:

image.png

六、完结撒❀:

       恭喜你看到这里,感谢阅读。

System.out.println("------------------------------------------------------------------------------------");

目录
相关文章
|
19天前
|
Java 开发者
【Java异常】什么是异常,Java中如何处理异常?
【Java异常】什么是异常,Java中如何处理异常?
30 0
|
19天前
|
Java 编译器
【Java】异常操作及自定义异常
【Java】异常操作及自定义异常
33 2
|
19天前
|
安全 Java 程序员
【Java 异常处理】异常处理机制,内置异常类,如何捕获异常
【Java 异常处理】异常处理机制,内置异常类,如何捕获异常
|
7月前
|
Java 程序员 编译器
[java进阶]——异常详解,try catch捕获异常,抛出异常
[java进阶]——异常详解,try catch捕获异常,抛出异常
101 0
|
10月前
|
SQL Java 程序员
java学会这些,我就入门啦!(基础篇三)异常讲解与常见的异常
java学会这些,我就入门啦!(基础篇三)异常讲解与常见的异常
|
11月前
|
Java 数据库
Java 中的异常类型、异常处理机制、最佳实践
Java 中的异常类型、异常处理机制、最佳实践
91 1
|
12月前
|
Java
Java中异常的抛出方式
Java中异常的抛出方式
369 0
|
Java 程序员
java运行时异常和抛出异常的区别
java运行时异常和抛出异常的区别 与张航日常交流的心得, 当在写事务回滚的时候, 我们会利用异常来执行是否提交和回滚。 异常分为运行时异常与受查异常。 运行时异常,是 RuntimeException 类或其子类,即只有在运行时才出现的异常。如, NullPointerException、ArrayIndexOutOfBoundsException、IllegalArgumentException 等均属于 运行时异常。这些异常由 JVM 抛出,在编译时不要求必须处理(捕获或抛出)。但,只要代 码编写足够仔细,程序足够健壮,运行时异常是可以避免的。 受查异常,也叫编译时异常,即在代码编写时要
143 0
java运行时异常和抛出异常的区别
|
Java
java中的异常(带你全面了解异常)
java中的异常(带你全面了解异常)
78 1
java中的异常(带你全面了解异常)