Java异常就是在一些情况下,程序报错,这就是报异常,告诉我们这个程序哪里出了什么样的问题.
如下图:
这就是一个异常,java.lang....就是异常的种类,后面跟的这个异常叫做算数异常,后面会跟着一个原因,为什么出这个异常,再下边就是在第几行出现的异常,
我们点进去这个异常的类型中可以看见
其实这个就是一个类,异常有很多种,这个是其中的一种
如上图,这也是一个异常,这个整形数组是null,也就是说这个数组不指向任何的对象,在我们打印它的长度的时候也会抛出一个异常叫做空指针异常,当没有处理这个异常的时候,程序会到此为止,然后抛出一个异常.
以上这几种异常是比较常见的额异常,上边的异常叫做数组越界异常,因为数组里只有4个元素,没有10这个下标.
异常的分类
异常分为编译时异常(受查异常),运行时异常(非受查异常),受查异常就是在编译时期可以检测出来的,非受查异常就是在编译的时候不能检测出来的异常.
比如我现在要写一个clone的方法,去克隆这个person类,这个类实现了这个克隆的接口,重写了clone的方法,但是现在还是报错的,所以从时期上来分,这个异常就属于编译时的异常(受查异常),因为还没运行呢,这个clone就报错了,所以这个就是受查异常.
可以看到,异常就是类-->throwable这个类的子类有error和exception,error是错误,exception是异常,
可以看到,当我无条件们递归循环调用func方法的时候,这个报错就是显示error,error代表这个错误是一个Java虚拟机无法解决的问题,这是一个逻辑上的错误,需要程序员手动排查的.
而exception是异常产生后,程序员同构代码的处理,让程序继续执行,
还有exception,它的子类有IOException和RuntimeException,就是受查异常和非受查异常,比如算数异常,空指针异常等等就是运行时异常(非受查异常),
异常的处理
要处理异常,首先要有异常:1.程序执行的过程中,自己抛出了异常, 2.自己手动设置模拟抛出异常.
上图就是我自己手动抛出一个异常,下面java:12 代表指定了直接抛出异常的位置,16代表出现的异常,一般的,如果上面的问题解决了,下面的就没问题了,一般用在自己自定义的异常.
如上图,这就是程序自己运行的时候抛出的异常.
如果抛出的是受查异常(编译时异常),需要我们手动去处理.
如果抛出了异常,程序就不再向下执行了.
throw必须写在方法体内部
异常的捕获
这个就是第一种具体处理异常的方式,当我们不写throws CloneNotSupportedException的时候,这个就会报错(受查异常),它需要我们手动处理异常,加的这句话就相当于当我在使用这个方法的时候,这个方法就告诉我,你使用这个方法,会抛出一个什么什么样的异常.
此时的这种方法去处理异常只是不报错了,当我们去执行这个程序的时候依然会抛出异常,如下图:
此时的声明只是为了让程序在编译的时候不进行报错了,下面打印fsfe的语句仍然不会执行.
所以说当我们没有真正的处理某种异常的时候,我们就会把异常交给jvm,一旦交给jvm之后,程序就崩溃了.
其实这个问题不大,但是就终端执行了,所以说这种方法是比较粗暴的,所以还有一种方法,可以解决当我们不想让程序中断运行的情况下,程序可以继续执行.
此时就用到了trycatch语句:
此时可以看到正常的逻辑在执行,catch语句种写处理异常的逻辑,处理完成之后,让程序继续执行,这个时候没有把异常交给jvm处理,才真正的处理了异常,catch语句可以写一个,也可以写多个.
这个地方报错的原因是当我们抛出受查异常的时候,此时检测不到就会报错.
当try种存在多个异常的时候,从上往下执行,谁先抛出异常,就捕获哪一个异常,和下面写的捕获的顺序没有关系.
如果try中存在的异常没有在catch中及时捕获,就会交给jvm处理,一旦交给jvm处理,这个程序就会崩溃,不会执行下面的语句了.
如果异常具有父子类的关系,要把子类异常放在前面,父类放在后面,因为子类的异常父类也可以捕捉到,那子类的存在就没意义了.
finally
finally的使用是在捕捉到异常之后,不管是否捕捉到了异常,都会去执行finally语句.
可以看到,不管是否捕捉到了异常,finally语句都会被执行,所以finally语句一般用于资源的释放,
上图展示了finally可以用来关闭资源,scanner也是一个资源,文件也是一个资源.finally总会被执行到,所以可以关闭上面消耗的资源,进行资源回收.
throw和throws的区别:throw用来抛出异常,throws用来声明异常.
还有不建议将return写到finally中,因为会把上边的return给覆盖掉.
异常处理的流程
这个流程是按照调用栈走的:
程序先执行try中的代码
如果try中的代码出现异常,就结束try中的代码,看try中的异常和哪一个catch匹配
如果找到匹配的异常类型就执行catch中的代码
如果没有找到匹配的catch类型,会将异常向上传递,也就是说比如在func方法中出现的异常,但是没有在func中处理这个异常,在main方法中调用了func方法,就需要在main方法中去处理这个异常
如果main方法中也没有处理这个异常,就 会交给jvm去处理,这个时候程序就会中断运行.