在Java中,将程序执行过程中发生的不正常行为称为异常(Exception)
错误是程序无法处理的,如OutofMemoryError(内存溢出),StackOverFlowError(栈溢出错误),VirtualMachineError(Java虚拟机运行错误)……
异常是程序本身可以处理的,可以向上抛出或捕获处理
1.Throwable类:是异常体系的顶层类,其派生出俩个重要的子类Error和Exception
2.Error类:是Java虚拟机无法处理的严重问题,比喻JVM的内部错误,资源耗尽等,一旦发生回力乏术
3.Exception类:此异常产生后程序员可以通过代码进行处理,使程序继续执行。我们平时所说的异常就是Exception
分为运行时异常和编译时异常
是RuntimeException类及其子类(NullPointerException空指针异常,ArrayIndexOutOfBoundException数组越界异常,ArithmeticException算数异常),是程序运行阶段发生的异常,也称为非受查异常,是程序已经通过编译得到字节码文件后再由JVM执行时出现的异常
编译期间的异常,从语法上讲是必须处理的异常,如果不处理,程序就不能编译通过,也称为受查异常
try后面是可能出现异常的代码,catch是想要捕捉的异常
当不用try catch时,JVM会自动处理异常,即直接终止程序运行,如下
而当用trycatch处理后,则如下:
没有打印haha
System.out.println(e.getMessage());//只打印异常信息
System.out.println(e);//打印 异常类型:异常信息
e.printStackTrace(); //打印信息最全面
先看前俩种打印方式:
再看最后一种打印方式:
但当把catch中的语句调换顺序后:
发现异常信息竟然在程序最后执行了
这是因为printStackTrace()方法是使用其他方法执行的,而不是单纯用println,所以会有时间延迟
也可以写到一个catch里面
因为一旦抛出异常,异常后面的代码就不会执行,直到将异常解决
如果写反了,就会如下报错:
这个就是异常的父类:Exception类
但不建议这样写,能详细些就详细些
就是上面提到的代码
如下代码
因为我们没有解决此异常,所以交给了JVM处理,即把程序终止了
那如何自己处理呢?还是用try catch,可以在test1函数中处理,也可以在test1函数的调用者main函数里面处理,如下:
或者:
以上是针对抛出运行时异常的,那如果是编译时异常呢,就没有这么简单了
编译时异常一旦出现就会导致编译不通过,就没法在运行时进行处理,这时就要用到throws关键字来声明异常,如下:
处理还是和上面一样
但当是在test1函数中处理异常时,main函数后面也要声明此异常,否则会报错:
下面是对的:
在一个项目中,某个方法可能被多个方法调用,当用来throws关键字后,就可以提醒调用者自己去处理异常,这时的处理方法就可以根据调用者的意愿来进行,但要是同意让方法自己处理,那处理方式就会单一,
如果调用者不想去处理异常,就也要在后面通过throws去声明异常,然后交给jvm处理
finally块中的代码,不管前面是否抛出或捕获异常,它里面的代码都会被执行到,如下
在写程序时,有些特定的代码,不论是否发生异常都需要被执行到,比如程序中打开的资源必须要在程序正常或异常退出之前关闭。但因为异常引发的跳转可能使某些代码无法执行,这时finally就起作用了:
比如Scanner资源的关闭:
结果如下,当我键入的不是int型数据时,就会抛出异常,但finally中还可以正常执行,并将scanner资源关闭
但是发现,finally后面的代码一样可以执行到,那为什么还要有finally?
看下面的例子:写一个函数,返回一个输入的数据>>:
当我们正常输入整形数据时,会在try中直接执行return语句,导致if语句执行不到,导致资源的浪费,而只有输入非整形数据时才能正常关闭。这种情况下就要用到finally关键字:
如下代码,当我们键入10时,main函数中接收到的是10吗?不是
结果接收到的是100.
用这个例子改写一个异常
先来看程序提供的异常:
都继承了Exception类,并且有俩个构造方法,我们模拟它来自定义UserNameException和PassWordException,这属于运行时异常,最好是继承RuntimeException
如何使用呢?如下:
此时在方法后面要声明异常,可以向上抛出到调用者让调用者处理,也可以自己处理,如果是自己处理,那调用者也要声明异常