还记得那首火遍大江南北的音乐《死了都要爱》么?在程序员群体中也有一首类似的歌:
歌名:《死了都要try》
歌手:程序猿
死了都要try
不抓住异常不痛快
BUG多深,只有这样,才不用重来
死了都要try
不catch够我不痛快
程序毁灭throw还在
把每天,当作程序来更改
一改一天,都累到泪水掉下来
不理会,老板是看好或看坏
只要有工资,来还贷
改,不是需求做的太坏
那是客户想要什么,自己都不明白
忍受现在,自己一生都还不完的贷
很多模块,不能完成,我还得改
死了都要try
不catch够我不痛快
程序毁灭throw还在
不得不说,这首歌的歌词简直不要太真实了,说出了广大程序员同胞的心声。
这首歌在说啥?
其实就是在说异常,其中里面的try,catch,throw,便是3个关键字。
一、异常的回顾
回顾下抓取异常的方式:
非常地好理解:
try:尝试的意思,也就是说这块代码可能有问题,我就尝试着把它用大括号框起来,以防它出错。
catch:抓取的意思,我先指定一个异常,如果try里面的代码出现了这个异常,就把它抓取了。
抓取有什么用?能保证程序不会蹦。
catch可以有多个,但是只能抓取对应的异常,数组越界异常只能用来抓取数组越界异常,出现其他的异常它就没法管了。
这就好比,这个国家的陆军只能管陆军,空军只能管空军一样。
但不管是陆军还是空军,国家都可以管。
所以Eception,无论是数组越界异常,还是字符串越界异常,它都可以管。
**finally:**无论怎么样,都会运行
再回顾下异常里的继承体系:
和程序员打交道的主要是Exception。
Exception又分有两大类:
- ParseException:编译异常,不解决没法运行,必须处理。
- RuntimeException:运行异常,编译期间可以不处理,但是可能发生在运行时期。
常见异常有哪些呢?不要被异常长长的一段字符吓到,其实只要拆开了看还是蛮好理解的。
ArrayIndexOutOfBoundsException
Array:数组;OutOfBounds:超出了界限。所以是数组越界异常。
StringIndexOutOfBoundsException
String:字符串;Index:索引;OutOfBounds:超出了界限。所以是字符串越界异常。
IllegalArgumentException
Illegal:非法的;Argument:参数;非法的参数。所以是非法参数异常。
NullPointerException
NullPointer:空指针。所以是空指针异常。
二、自定义异常
在开发过程中,我们要遇到的问题可以说是很多很多的。
那么问题来了,Java里面定义的异常是很有限的,一共就那么些异常,所以有时候就需要我们自定义异常来说明情况。
在Java里面,一切万物就可成类,自定义异常,就是自己创建一个异常类。
- 编译期异常:自定义类并继承于Exception
- 运行期异常:自定义类并继承于RuntimeException。
比如说现在有一个类Person,它有姓名和年龄两个属性:
现在有个用户填年龄时就是要填-18岁,怎么办?
很显然,年龄是不可能-18岁的,如果类的成员变量没有封装,用户是直接可以随便修改的,显然这样是不行的,所以封装的作用就出来了。
什么叫封装?
通俗点说就是:用户没法直接修改属性了,而是通过方法修改,这样的话,我就可以在方法里面加一个判断,你若是输入的数据不合适,你就没法修改属性成功。
这就是封装的意义。
好,现在我们在方法里,设定一个年龄规则,用户输入的数字若是不在这个范围里面,就会抛出异常,并且提醒用户。
好,现在问题又来了,产品经理看了之后,觉得你写的这个RuntimeException它看不懂,他要年龄异常(ArgException),这样更加地直观。
可是Api里面又没有ArgException这个异常。
要知道产品经理是会对程序员提各种各样的需求的,原则上程序员是需要满足产品经理提的要求的,但是有些产品经理又不怎么懂技术,就会乱提要求。
我记得有一年平安的产品经理就和程序员发生了矛盾,双方大打出手,还上了热搜,闹得沸沸扬扬的。
当时产品经理提的要求好像是:
用户使用平安APP时,APP界面颜色要和用户的手机壳颜色一样。
当时程序员就觉得,这怎么弄?没法做,产品经理又要做,于是两个人就打起来了。
当然,这个需求能否通过技术上的手段解决我也不清楚。
回到我们自定义异常的问题,产品经理说要ArgException,怎么办?
自定义一个异常就好了。
异常里面的底层到底是如何处理的,我们清楚么?
我们不清楚,那不清楚怎么写?
这个时候,面向对象第二个特性:继承的作用就出来了。
我不需要知道怎么写,我只需要继承某个异常就好了,父类是怎么处理的,我直接使用它的方法就好了。
这就是自定义异常,特别简单。