这一篇内容比较长,超过限制了,另附一小段,接上篇。
09-面向对象(自定义异常)
因为项目中会出现特有的问题,而这些问题并未被Java所描述并封装对象。
所以,对于这些特有的问题可以按照Java的对问题封装的思想,将特有的问题,进行自定义的异常封装。这就是自定义异常。
还是以刚刚的程序为例:
现在自己封装一个异常,注意命名方式都是按规范的来的哦:
先不用给里面写什么,我们现在建立它的目的只是为了生成对象。
我们自定义的异常,Java不认识,这个时候就需要我们手动建立对象,并进行抛出。(之前都是自动抛出,现在是手动抛出)
注意是throw不是throws哦:
试一下运行:
一个小技巧:但凡在编译的时候出现这个错误提示的时候,恭喜你,你已经解决到了语法错误的最后环节啦!在编译的时候,它先报的是最基本的语法错误,如果没有语法错误,有异常的问题,它会最后报告。所以,当出现这个问题的时候,说明你的编译问题已经解决到最后了,只要把这个问题解决掉,编译就通过啦!
继续我们的问题。
当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作。
要么在内部try catch处理,要么在函数上声明让调用者处理。
一般情况下,在函数内出现异常,函数上需要声明。
所以我们声明一下异常:
再运行,继续报错:
继续写try-catch语句进行处理:
给里面传一个负数,运行,成功啦:
我们发现,这个异常木有信息。因为我们没有定义信息哦,刚刚那些Java已经封装好的异常有具体的信息,是因为它们已经定义好信息啦。
那么如何定义异常信息呢?
给自定义的异常添加一下内容:
然后在Demo类中传一个异常信息:
编译,运行,这下就有信息了:
但是我们翻一下手册,发现父类Throwable中已经定义了这些功能啦,把它简单还原一下大概这样:
我们再看看它的子类Exception:
我们发现,Exception中没有方法。但是它有一个带有String message参数的构造函数。
再次还原一下:
既然父类已经定义了这个方法,子类就不用重新写啦,直接将它传给父类处理就OK啦。
所以,刚刚我们写的那些都很多余,这样写就行啦:
试一试,成功啦:
因为父类中已经把异常信息的操作都完成了。所以子类只要在构造时,将异常信息通过super语句传递给父类。那么就可以直接通过getMessage方法获取自定义的异常信息。
接下来,我们对于自己定义的问题,想有自己特有的信息,比如,想拿到到底是哪个负数值出现了问题。
这样写:
在Demo中将这个错误的b传进去:
用catch输出一下b的值:
运行:
这就是我们的自定义异常。
注意,在自定义异常的时候:
自定义异常类必须继承Exception。
继承Exception的原因:
异常体系有一个特点:异常类和异常对象都需要被抛出。它们都具备可抛性,这个可抛性是Throwable这个体系中的独有特点。只有这个体系中的类和对象才可以被throws和throw操作。不是随便定义一个类就能抛的 。
10-面向对象(throw和throws的区别)
throw和throws的区别:
1,throws使用在函数上,throw使用在函数内。
2,throws后面跟的是异常类,可以跟多个,用逗号隔开。throw后面跟的是异常对象。
什么是函数上?
要写在小括号和大括号之间的这里:
11-面向对象(RuntimeException)
刚刚我们自定义了一个异常,抛出的是我们自定义的内容,现在能不能在这个自定义的异常里面,手动的来抛出一下算数异常呢?
算数异常中有两个构造方法摘要:
我们在Demo中throw一个算数异常对象:
编译运行:
抛一下Exception试试:
编译失败了:
为啥ArithmeticException就没事呢?刚刚不是说函数内抛一定要标识吗?
这是一个非常特殊的地方。
ArithmeticException往上看,它有一个父类:RuntimeException,就是这个异常类,它非常的特殊。如果在函数内抛出了,函数上不用声明。
还有一个就是:
按理说,声明了一个抛出异常的方法,主函数需要写try-catch语句进行处理,但是现在我们试试主函数什么都不写编译一下,图略,发现编译并没有报错。
Exception中有一个特殊的子类异常:RuntimeException(运行时异常)
如果在函数内抛出该异常,函数上可以不用声明,编译一样通过。
如果在函数上声明了该异常,调用者可以不用进行处理,编译一样通过。
为什么它这么特殊呢?
之所以不用在函数上声明,是因为不需要让调用者处理。当该异常发生,希望程序停止。因为在运行时,出现了无法继续运算的情况,希望停止程序后,由程序员对代码进行修改。
我们看看Runtime都有哪些子类:
它里面有很多我们常见的异常,比如空指针异常。
一个空指针异常的例子:
name都没有值,根本没办法继续运行,只能让程序停下来,我们修正一下自己的代码,才能让它继续运行。
怎么修正才能避免这种情况的发生呢?
写成这样就好啦。
在上面的例子中,我们并没有抛出异常,最后程序停掉了,我们才能发现了这个问题并修正它呢。
自定义异常时,如果该异常的发生,无法再继续进行运算,就让自定义异常继承RuntimeException。
试一下:
因为没有声明异常,所以注意主函数中也没有处理它哦,运行:
这时候程序停下来了,程序员就会进行对自己的代码进行反思:符合条件的值往进传,不符合条件的值就不传啦。
接着看。
Object类中有一个void wai方法:
这个方法什么作用我们这里先不用管~
我们点进这个方法看一下:
我们发现,这个方法会抛出三个异常,可是我们又发现,在函数声明的时候,只抛出了一个异常:
还有两个,它没有声明。因为它们都是RuntimeException的异常。(你敢做这件事情,它就敢让程序停下来,哼!)
所以抛出的异常说明它对程序的影响不大,不抛出的异常对程序运行影响很大,我们必须让程序停下来好好反思一下,修正一下。
所以下回在自定义异常的时候,我们有两种选择:继承RuntimeException,或者继承Exception。
面试的时候也经常会考这里,会问它没有抛出能不能编译通过呀?(不要傻傻说不行哦)
对于异常分两种:
1,编译时被检测的异常。(比如Exception异常,这个时候要抛出,让调用者去处理,因为它是可处理的。而声明的异常,调用者也必须写try-catch语句进行处理,或者进行抛出)
2,编译时不被检测的异常(运行时异常。RuntimeException以及其子类)
所以在自定义异常的时候,我们要考虑,这个问题是否可以被处理,如果可以,就继承Exception异常,让调用者去处理。如果不可以,就继承RuntimeException异常,让程序停下来,我们好好修正。
12-面向对象(异常练习)
接下来,通过一个示例,来讲一下异常的应用。
需求:
Teacher类:
Computer类:
走一遍:
接下来开始分析问题。
我们讲课的过程中,会出现各种各样的问题。比如:电脑蓝屏,电脑冒烟。
这个时候对问题进行描述:
1,蓝屏发生后,可以进行处理,所以需要标识出来异常。
2,冒烟发生后,我们分两种情况分析一下。
先继承Exception。
我们定义一个值state,如果它为1,表示正常。如果它为其它值,表示出问题了。
如果蓝屏,我们就让它重启:
重启就让它的状态恢复到1了,这时候给重启函数中加一句:
如果冒烟了,会出现讲课进度无法继续,这个时候,出现了讲师的问题:课时计划无法完成。这时候需要定义一下讲师的异常:
所以冒烟时,抛出讲师的异常:
注意test的调用要放在throw前面哦,放在后面就不会被执行到。(return语句也是这样,放到它后面就不会被执行到了)
主函数中:
编译运行:
到这里问题基本解决啦,但还有一个可以完善的地方。换老师或者放假总得有个理由吧,我们改成这样:
主函数中加一句这个:
编译运行:
心好累。