


如何自定义异常。 这个东西在咱们生活中其实用的并没有那么多。 为什么?我们之前说了, 咱们Java, 你看往回看, 我们Java里面它已经给我们定义好了 非常非常多的异常, 而且别人那些开源框架里面也有自己对应的异常。 所以说,如果你不是去写开源框架, 或者你不是写一些大型系统的话, 很少去用到这个知识。 但是掌握这个知识还是非常有必要的。 那咱们来看一下,使用Java内置的异常类可以描述什么? 在编程时出现的大部分异常情况,就相当于什么? 我们加上内置的那些东西就已经够了。 什么类找不到啊, 类加载失败啊,等等这样一大堆的异常。 那除了这些东西之外呢? 假设我自己定一个,想 比如说叫狂神Exception, 对不对? 那这个异常的话,就是咱们自己写的一些异常类。 是用来处理一些自己的一些小问题的, 也可以使用它。 那咱们来看一下。 首先我们第一步要创建一个异常类, 第二,我们可以在方法中去抛出这些异常, 然后抛出完之后呢, 可以通过try catch去捕获它。 对不对? 那咱们去写下代码看一下。 其实自定义异常非常简单, 你只需要继承Exception类就可以了。 就是你写一个类去继承它。 我们来个Demo, 02诶, 从这一节课之后,以后 把这个Demo换成Lesson了, 就是课程,我觉得更形象一点。 用Demo的话,总感觉太小了。 对不对? 比如说咱们来写一个自己的异常MyException, 我们可以看到这是我的一个自己的异常类。 对不对? 但是它现在并不是一个异常类, 因为为什么?它必须要去 是不是要去继承咱们的Exception类呀? OK,一旦你去继承了Exception类之后, 那么你这个类就是什么? 是自定义的异常类了。 自定义的异常类。 那你们可以看到这个Exception里面它是有非常非常多子类的。 你点开这个箭头, 你看它Java里面给我们重写的这个东西, 你根本看不完。 你看旁边还在加载, 你看太多异常了。 看这个是Java里面内置的。 估计成千上万个,当然没有那么吓人。 你可以看到这边这个进度条, 这里面就是它全部的。 这些异常的话,几乎满足了我们大部分的需求。 所以说一般情况下我们不用自定义, 但是来掌握一下就好了。 来,我们这个地方自定义一个MyException, 然后我们就写一下这个异常的一些方法。 可能很多人觉得无从下笔,是吧? 异常了该怎么定义? 我们可以去看一下别人的, 对不对? 比如说我们随便找一个ClassNotFound, 或者咱们之前学的数组下标越界,是吧? ArrayIndexOf, 咱们来去搜一下。 看一下上面有没有IndexOutOfBounds。 对不对? 你看这样的话, 我们就来到了别人写好的异常类, 然后它这个异常类呢,它继承一个父的异常类,是吧? 那咱们可以去看一下它的父异常类, 然后到这个地方, 它是继承了一个运行时异常, 然后再往上走, 诶, 它继承了Exception, 所以说它是好几个子类下面的。 对不对? 它继承了四层关系。 那咱们来看一下这个异常它是怎么写的。 首先它这个地方是不是有个构造方法呀? 可以看到构造方法里面是空参的, 就是什么都没有, 是调用父类的。 那这构造方法里面它也可以接收一个下标, 看到了吗? 就是如果这个下标来了, 它要怎么抛出, 然后还是调用了一些父类的方法。 哎,这下面也是一样。 那咱们可以点一下这个父类的方法, 看一下这个父类的方法, 它又调用了父类方法,是吧? 那再调,诶, 这个地方还调用了父类方法。 这个地方就是什么? 是不是就一个message啊? 这个就是咱们Exception message了。 说白了,它就是 你看它要是打印这个message, 它也是个detail, 对不对? 那咱们也自己来写一个描述信息。 那比如说我们等会儿要给他传一个数字, 传递数字, 我们要去判断, 这个数字它如果大于某个数, 比如说这个数字大于十, 我们就给他抛一个异常:数字,数字。 那假设我们等会给他传递数字, 它大于十, 我们给它抛出异常。 那这个抛出异常的话, 它需要给人提示一些信息,是吧? 我们可以去写一些信息。 首先咱们来接收一下这个数字吧, 比如说就叫detail。 拿过来之后, 我们按照人家的要求, 是不是写一个 写一个构造器就可以了。 那我们也构造器把它丢进去。 Alt加Insert, 来一个Construct构造器, 然后写一个消息的构造器。 那咱们可以看到现在的话,这个地方就已经写了构造器, 我们可以把自己的一些消息传进来。 当然我们这个地方传递的是谁呀? 是不是应该把咱们这个detail给传过去, 然后去让他去输出这个detail的信息。 那咱们来试一下。 比如说咱们经常定义一个int类型的a这个东西, 等会儿我们可以给它传递。 来,小写的int a,那咱们这个地方给他传一个参数之后, 我们这下面就可以去把这个detail赋值了。 detail等于a,那当然如果你们为了看的更清楚, 是不是可以加个this啊? 那咱们这样一个简单的Exception就写好了。 然后如何让别人去打印出这个信息呢? 我们需要写一个非常重要的方法, 叫做toString,咱们之前也学了,toString是打印信息的,是吧? Alt加Insert, 然后回车,看到下面有个toString方法, 然后OK,这样的话咱们就可以实现了一个自定义的异常。 你可以看一下咱们这个地方就接收了一个参数, 然后去判断, 然后这个地方写一个异常的信息。 你们可以把这个地方就理解为异常的打印信息, 异常的打印信息就OK了。 那这个异常的话, 你们也可以自己去拼接, 要怎么好看就怎么好看。 如果你们觉得这样丑, 那你们就把它变得好看一点也可以。 当然我们就用它一个默认的消息, 或者就直接写个异常吧。 那这样就可以了。 你看MyException加一个detail描述。 OK,这是咱们写好的一个异常类。 那咱们现在要去写一个测试类, 对不对? 我们来一个Test, 那咱们来一个Test去测一下咱们的异常。 首先我们要写一个可能会存在异常的方法, 对不对? 可能会存在异常的方法。 那咱们来看一下可能会存在异常的方法。 比如说咱们这个地方有个方法, 比如说来计算一个数, 嗯, 或者说传一个方法就叫test,来 这是咱们的一个测试方法。 这个方法的话,我会在里面可能会抛出异常。 比如说我也给他传递一个参数, int a,那咱们就要判断了。 假设这个a, 它大于了十, 就相当于超过了我们刚才预定的范围, 我就要抛出一个异常了,throw。 你看,就抛出自己的异常:new一个咱们的MyException, OK,MyException里面需要去传递它传入的值是啥, 就来了个a。那假设我们这个地方抛了异常, 他就会告诉我们, 那他说这个地方有一个未知的异常, 对不对? 你需要 你需要把它给处理一下。 看你要么在这个地方捕获, 因为这个地方存在异常嘛。 第一种方式你可以在这里捕获, 第二种方式就可以 把它抛出去, 抛到更高的地方, 让调用这个方法的人来捕获它。 那咱们来试一下。 这个里面既然有存在异常的话, 我们在这个地方选择了抛出, 对不对? 你们也可以选择在这里面捕获。 这里面捕获了, 外面就不用捕获了。 你现在抛出去了, 外面也要捕获。 反正欠的债总要还, 对不对? 那咱们来看一下。 如果大于十就抛出, 如果没有大于十, 那咱们就输出一些咱们的OK,结果是正常结束的。 对不对? 那咱们这个地方可以传递一下进来的数, 比如说,传递的参数为: 那这样的话咱们就可以看得非常清楚了。 OK,咱们这个方法就写完了。 你调用这个方法肯定会抛出一个异常, 你要去把它捕获来。 来,psvm, 咱们写个方法来测一下。 首先的话我们还是来, 首先咱们来调一个test, 比如说我给他传个一, 你看你要这个的话, 他就会说他抛出了一个异常, 对不对? 咱们要去把它捕获下来。 try catch, 你看try catch捕获它,这个地方捕获的就是谁? 是不是咱们自定义的MyException? 然后它会打印出一些信息。 那打印的信息这个e的话, 我们就不需要,这个e其实就是我们的一些消息。 我们可以把这个消息给他输出一下, 输出一下就好了。 比如说写个MyException, 然后, 然后这个地方加上咱们的一个e, 对不对? 就是咱们这一个自己的一个消息。 OK,那咱们现在正常跑的话, 咱们知道这个一,他是不是应该输出 OK,不走这个异常。 那咱们可以来测一下。 那这样的话你就可以把异常理解清楚一点了。 来,我们来看一下它这个最终的一个运行结果。 OK,看传递的参数为一, 那么它是不是正常结束的? 他没有走这个异常。 那咱们如果传递一个十来看一下呢? 这个十的话它不大于十, 对不对? 那走一下来。 我们来看一下最后的一个效果, 看一下他是什么样子。 可以看到传递的参数 10,是OK。 那传个11, 11大于十, 那么他一定会走这个异常, 对不对? 那咱们再来走一下。 哎,刚才这个十是等于它的, 也不大于它。 那咱们来看一下。 现在就走了这样一个东西。 首先咱们的程序看一下怎么运行的。 我们调用了这个方法之后, 对不对? 它接受了传递参数为11, 如果a大于10, 它就抛出了异常。 这个地方抛出异常了之后,被这边try catch捕获到了。 捕获到了之后,是不是就走了这个捕获块里面东西? 然后这个地方也就输出了MyException, 它输出来的什么东西? 这个e,你看这个e就是咱们这边的toString方法, 对不对? 打印出来了一些异常的消息。 所以说咱们正常定义的一些异常错误的消息就是这个detail。 你们可以根据自己的需求传递不一样的东西, 自定义常量。 说白了就一个核心: 你自己写一个异常类, 继承Exception就好了。 然后这个类里面处理一些你可能会觉得出现异常的一些问题, 最后把它这个消息打印出来, 打印出来。 别人只要去抛出了这个异常, 我们把它捕获到, 我们打印它的一个信息, 就可以得到它最终的一个结果了。 自定义异常的话, 其实用的并没有那么多, 因为咱们之前说了, 是不是正常情况下咱们的Java里面, 你看这Exception里面它的类就已经非常非常的多了。 你只要去看的话, 下面的异常太多太多了, 你都用不完。 所以说正常情况下掌握这个技能, 看到这种代码的时候, 你要知道该怎么做, 接收到这种异常的任务, 你需要知道该怎么去处理这个东西就OK了。 那咱们来总结一下。 就把这个异常, 因为东西并没有那么多, 这一章的话, 那咱们来看一下, 在实际经验中的一些总结。 这个是不是很重要啊? 这就是实际应用的一些经验。 首先来看一下咱们在处理 运行时异常的时候, 尽可能 看到合理的规避, 同时辅助咱们的try catch进行处理。 因为用了try catch, 咱们程序就不至于突然一下给它卡死, 对不对? 这样的话情况就比较少了。 第二个,假设我们用多重catch的话, 我们尽可能加一个最大的异常, 比如说catch Exception, 对不对? 因为有些小异常可能我们抓不到, 但是程序运行中出现了, 程序运行中出现了这个try catch Exception, 这是最大的异常的类, 它就可以去处理得到。 所以说这样的话是一个比较高效的方法。 第三个, 对于一些代码不确定, 我们不知道它会不会出现异常的, 可能会存在一些潜在异常, 我们也给它加一个try catch代码块。 但是咱们的IDEA里面就是假设有异常的话, 它一般会 他会给你报一个红色的波浪线, 然后这时候你需要 按住Alt加什么? 这个东西它会自动帮你去提示一些东西该怎么处理。 非常万能的一个键。 那除了这个之外的话, 咱们说了尽可能的处理异常, 尽量的不要只是去调用咱们的打印这个输出, 因为这个地方是咱们的默认信息, 对不对? 咱们用快捷键生成咱们的异常块之后, 它默认就帮我们打印这信息。 你要在这个里面去 就比如说咱们刚才这个东西, 这个地方假设我们这个地方不是去捕获了它, 对不对? 我们这方拆开之后, 我们要在这个地方做一些小写输出, 我们要看一下怎么能拯救它。 比如说假设它传的是11, 我们可以在里面加一个处理: if, 它大于了10, 就是这个, 然后我们就给它 自己手动加一些判断, 然后让它变小就可以了。 就是你可以加一些代码块进行处理。 这里就是增加一些处理异常的代码块, 增加一些处理异常的代码。 这个地方的话就可以让咱们的损失变到最小。 所以说大家只需要慢慢的去吸收理解就好了。 这个地方就是一些基础知识, 以后, 你遇到每一个咱们都会详细的给大家讲解咱们真实的业务情况下, 你只能根据不同的业务去处理, 对不对? 不同的异常。 因为你可能在银行公司, 可能在金融公司, 可能在一些互联网公司, 可能在小公司, 可能是大公司,遇到的需求各不相同。 所以说只能根据实际情况去处理, 并不能说在这个地方三节课大家就把它搞定了, 对不对? 最后看,尽量添加finally语句块去释放一些占用的资源。 这个在咱们之后会强调, 尤其在IO流的时候, 会给大家一直用到,持续用到。 咱们现在你们可以回过头去看一下咱们的Scanner, 你们可以选择清空, 把这个运行异常都捕获一下, 看一下程序还会不会像原来那样子。 比如说你要输入一个String, 你给它输入个int, 它就停止了。 加了try catch就不会了。 这样的话就非常非常的高效。 OK,关于异常的话, 咱们就聊这么多,以后 遇到每个异常, 咱们再详细的去说每个异常的一些作用, 然后再去加深大家的一个理解就OK了。 OK。