java抛出异常代码_“全栈2019”Java异常第十一章:重写方法时只能抛出父类异常子集...

难度

初级

学习时间

30分钟

适合人群

零基础

开发语言

Java

开发环境

  • JDK v11
  • IntelliJ IDEA v2018.3

友情提示

  • 本教学属于系列教学,内容具有连贯性,本章使用到的内容之前教学中都有详细讲解。
  • 本章内容针对零基础或基础较差的同学比较友好,可能对于有基础的同学来说很简单,希望大家可以根据自己的实际情况选择继续看完或等待看下一篇文章。谢谢大家的谅解!

1.准备继承类

这里我们准备两个类,它们是继承关系,子类为Zi,父类为Fu。

Fu类:

2f041a2bb282134bb18f0bd9f2c183c6.png

Zi类:

6f4ab80f9985e572826254791120dac7.png

2.准备重写方法

那么接下来呢,我们就在Fu类中写上一个成员方法,然后让子类去重写这个成员方法。

Fu类:

f5879c8af2dd5b159041a13448fd82fd.png

Zi类:

5ec8ceeebc3c88bca410872a85d9ec07.png

3.父类中成员方法抛异常

子父类也有了,方法也重写了。接下来就是在父类方法上抛出异常,然后观察子类方法会出现什么错误。

演示:

请给父类方法抛出一个异常。

请观察程序运行结果。

代码:

Fu类:

2a358659033691ff3278e4faaa2ad654.png

Zi类:

f5eb4ecd790b25cc60eacdeac238ebb8.png

Main类:

cb7931fe4f551077b931ab9137794d8c.png

结果:

ce47e7ab70fb93957898bfe9e37f8251.png

错误信息:

7e10fa46c4f9a1b6087993c72d03206d.png

文字版:

Information:java: Errors occurred while compiling module 'Hello'

Information:javac 11 was used to compile java sources

Information:2019-01-02 23:13 - Compilation completed with 1 error and 0 warnings in 3 s 113 ms

/Users/admin/Workspace/Java/Hello/src/lab/Zi.java

Error:(13, 18) java: 未报告的异常错误java.io.IOException; 必须对其进行捕获或声明以便抛出

从运行结果来看,我们程序出现了一点小小的错误。

错误信息显示,我们没有对一个叫做“IOException”的异常进行try-catch或throws。

首先,我们先得知道为什么会出现有“异常需要捕获或者声明”这个错误?

只有调用有可能产生异常的方法,才会出现此错误。

那就是说我们调用了会产生异常的方法?

是的。

哪段程序调用了会产生异常的方法?

首先从Main类中的main()方法来看:

3a973d8d4d3813a5e051560c8f7f9d1c.png

从代码块中可以看到,我们创建了子类对象并调用了其say()方法,那么,say()方法会不会产生异常呢?我们来看看:

66ac651fd6ff8a81e1987354c970b6c1.png

从程序代码来看,子类中的say()方法并没有声明说会产生异常,所以子类中的say()方法被调用时不会产生异常。

再来看子类中的say()方法里面:

c7edf2614bd6100d729bd92914365f83.png

子类中的say()方法里面调用了父类的say()方法,我们再去看看父类中的say()方法:

b5eae52b3836fe0e894dbb968a6446d2.png

首先我们看到父类中的say()方法上使用throws声明调用此方法有可能产生异常,而且该异常是IOException,好像问题的源头已经找到了,但最终是不是调用了父类中的say()方法产生的异常呢,再往下看。

父类中的say()方法里面:

1c6140a9db1291bd0d39dc56d23e9897.png

好,这段代码已经明确要抛出一个IOException异常,因为if的条件表达式为true,所以if语句里面的代码必定执行,也就抛出了IOException。由于IOException是一个非运行时异常,所以需要try-catch或throws处理,父类中的say()方法选择的是throws,将其声明在方法上。

这里就解决一个问题:IOException从哪里来的?

IOException是调用父类方法来的。

对于有throws声明会产生异常的方法,调用者只有两种处理方式:try-catch或thorws。

我们来看看子类调用父类有可能产生异常的方法处理方式是什么:

ef7bdb4d7e50f7b58ab25c7e29f10447.png

从程序代码中看,很遗憾,什么处理方式都没有,所以程序会报错。

虽然错误被我们找到了,但是我还是要跟大家说声抱歉,因为这个错误其实可以从错误信息中看出来,但我还是一步一步带领大家来找,其实是希望大家可以把之前的知识回顾一下,比如父子类方法之间的调用、抛异常以及声明异常。

错误点被我们找到了,我们待会来处理它。现在我们来看看如何通过错误信息来看:

/Users/admin/Workspace/Java/Hello/src/lab/Zi.java

Error:(13, 18) java: 未报告的异常错误java.io.IOException; 必须对其进行捕获或声明以便抛出

错误信息中告诉我们在Zi类的第13行代码处,有一个未报告的异常错误java.io.IOException; 必须对其进行捕获或声明以便抛出。

daa7b82bd8d60779df5e79cf33aa03ee.png

我们调用父类方法的地方正是在13行,错误点也被找到了。

接下来,我们对其进行处理(try-catch或throws):

try-catch:

05ad62e089d58896437f1d2710c4042c.png

throws:

f8c61a21beaadc19b87998520ac2ac1e.png

上面我们分别演示了try-catch和throws两种处理方式。try-catch这种方式最实用和最便捷,也不会出错。但throws情况又不一样了,下面就来讨论throws在继承中有哪些需要注意的地方。

4.抛出新异常

什么叫抛出新异常呢?

就是抛出父类方法已经声明的异常列表里面没有的异常。比如上节例子中父类的say()方法声明的异常列表里只有一个IOException,我们只需抛出非IOException的异常都叫抛出新异常。

好,我们来试试。

注意:

我们演示程序中抛出的异常都是非运行时异常,这是因为非运行时异常必须try-catch或throws,所以下面选择的新异常也是非运行时异常,有可能大家会觉得这几个异常和程序没有什么关联,对的,我们仅仅是为了演示,实际开发中不是这样的,请大家谅解!

Fu类不变:

0c5f18605d60f1cfea34219f96fdad8c.png

Zi类say()方法抛出新异常ClassNotFoundException,ClassNotFoundException是一个非运行时异常:

830f87cad041c37b9b17e1f8d8c4ceaa.png

既然Zi类say()方法抛出异常,那么调用者需要对其进行处理:

618f7813921d9f81be65b9b273e60de9.png

运行程序,执行结果:

9b45a69fe0e7358940f3f4486d1e9052.png

错误信息:

f74a9d7453e636e4aa03f85b993fcb15.png

文字版:

/Users/admin/Workspace/Java/Hello/src/lab/Zi.java

Error:(14, 17) java: lab.Zi中的say()无法覆盖lab.Fu中的say()

被覆盖的方法未抛出java.lang.ClassNotFoundException

从错误信息中我们可以看出,在Zi类的第14行代码处,这就下面这段代码:

0c1a2dbb8f0c40df873a4fc471b0677b.png

错误原因:Zi中的say()无法覆盖lab.Fu中的say()

发生子类方法无法覆盖(即重写)父类方法,我们之前学过方法的重写,它需要子类方法和父类方法一摸一样,这样才能发生覆盖。

那么,这里不能发生覆盖的原因是什么呢?

不能覆盖的原因是被覆盖的方法未抛出java.lang.ClassNotFoundException

被覆盖的方法是指哪个方法?

父类的方法。在本例中指的是Fu类中的say()方法。

换言之就是:Fu类中的say()方法未抛出java.lang.ClassNotFoundException

我们就可以得出结论:当重写方法时,只能抛出父类方法声明的异常列表中的异常,不能抛出新异常。

这只是当父类方法抛出一个异常时的情况,当父类方法抛出多个异常时,情况又会是怎样呢?

5.抛出异常子集

大家注意看清楚本小节标题,是抛出异常子集,不是抛出异常子类。

既然是子集,那么声明的异常肯定是在两个或两个以上。接下来,来改写Fu类:

b8453115e074c730f68567bc4ba7408b.png

Zi类不变:

7b865a98969ee8d339a2c24fbdf9d3d1.png

Main类处理异常行为发生了改变,打印输出语句也是方便大家观察:

e82f7b599485621491d5a7923e8cb6d5.png

运行程序,执行结果:

7a811242e499c6dc4026922d936a9ab0.png

这个执行结果是正确的,程序没有问题。我们来简单分析一下程序代码。

首先,我们在父类方法中抛出两个异常并使用throws进行声明:

4004dc2dbfdcb3f589ebdf6928b9a99d.png

然后子类对其方法进行重写并调用父类方法,将父类方法产生的两个异常抛出:

f5c320abb0ecc6b46180eb3b7143642e.png

最后,我们在Main类的main()方法中创建子类对象并调用say()方法,对抛出的异常处理:

8875d364ca865fa1ff3076d53829d4ee.png

执行结果:

f8e239cdca5c7ffeffd49c403c6c09d4.png

本例子主要演示了父类方法抛出多个异常,子类方法在重写的同时又去调用了父类方法,因为父类方法会抛出异常,所以子类方法必须进行处理(try-catch或throws),我们选择throws,这时父类方法抛出多少个异常,子类方法也必须抛出和父类一摸一样的异常。

有同学就有疑问了,我能不能捕获一个异常,然后其他异常将其抛出?

可以。

我们来试试,更改Zi类:

107f880ff422126e1cefdb10f19fa074.png

我们子类将父类方法中抛出的两个异常IOException和ClassNotFoundException,一个进行捕获,一个进行抛出,IOException被捕获,ClassNotFoundException被抛出。

这样的话,我们的Main类也是需要更改的:

0ed5db9ae3c6eeb3826114d35619287d.png

运行程序,执行结果:

4f3c63159c2e4cecf98157bf250c9e4b.png

从运行结果来看,父类方法抛出的异常被我们子类捕获到了:

34c2c6cdea63670da23fdb7f33ef3c0b.png

我们子类抛出的异常被调用者捕获到了:

b0d506b3b31dd9104a3ceadcd8d4bc29.png

本例子演示了我们子类方法可以抛出父类方法异常子集,本例中父类方法异常列表中有两个IOException和ClassNotFoundException,但我们子类只抛出了其中一个ClassNotFoundException。这就是子类方法抛出父类方法异常列表的子集。

6.需要注意的地方

第一个需要注意的地方,实际开发中,我们有可能是不调用父类方法的:

44af938b8f839f71a910b84ec2f315ce.png

这样就意味着,只要我们子类中不抛出异常,那么就没有必要声明异常。

第二个需要注意的地方,实际开发中,我们可能会产生新异常,这里千万不能抛出,只能try-catch(面试考点):

19eea0ab7c03f42be33c4056247fd131.png

当重写方法时,子类方法中出现新异常,只能try-catch,不能抛出。

当重写方法时,子类方法中出现新异常,只能try-catch,不能抛出。

当重写方法时,子类方法中出现新异常,只能try-catch,不能抛出。

重要的事情说了三遍,希望大家记住,非常重要,实际开发中很常见。

第三个需要注意的地方,我们能不能抛出父类方法抛出的异常的父类?

答案是不可以。

“我们能不能抛出父类方法抛出的异常的父类?”这句话有点绕,我们来分词看:

我们 能不能 抛出 父类方法抛出的异常 的父类?

换言之,父类方法抛出IOException,子类的重写方法能不能抛出IOException的父类Exception?

这肯定不能,比如说,父类抛出一只狗,你子类却抛出一个动物,这显然不合适,因为动物有很多,猫也是动物,我怎么知道你子类抛出的动物是狗还是猫,还是其他的什么动物。换作异常也一样,我父类方法抛出的是IOException,你子类却抛出Exception,Exception子类有很多,比如ClassNotFoundException,我怎么知道你到底抛的是IOException还是ClassNotFoundException,这显然就不对了。

当重写方法时,子类方法不能抛出父类方法异常的父类。

这个在实际开发中也很常见,希望大家注意。

总结

  • 重写方法时只能抛出父类异常子集。
  • 当重写方法时,只能抛出父类方法声明的异常列表中的异常,不能抛出新异常。
  • 只要我们子类中不抛出异常,那么就没有必要声明异常。
  • 当重写方法时,子类方法中出现新异常,只能try-catch,不能抛出。
  • 当重写方法时,子类方法不能抛出父类方法异常的父类。

至此,Java中重写方法与异常相关内容讲解先告一段落,更多内容请持续关注。

答疑

如果大家有问题或想了解更多前沿技术,请在下方留言或评论,我会为大家解答。

上一章

“全栈2019”Java异常第十章:throw与throws区别详解

下一章

“全栈2019”Java异常第十二章:catch与异常匹配

学习小组

加入同步学习小组,共同交流与进步。

  • 方式一:关注头条号Gorhaf,私信“Java学习小组”。
  • 方式二:关注公众号Gorhaf,回复“Java学习小组”。

全栈工程师学习计划

关注我们,加入“全栈工程师学习计划”。

6f9e162e64af8ef641fb16758d98b67a.png

版权声明

原创不易,未经允许不得转载!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值