前言
过去学习Java的时候碰到异常处理机制,感到很新奇,但是学习中充满许多疑惑,也因为某些原因自己没有去实现以及进一步学习,一直作为我心中的一个难点。时隔1年后,我又一次重新回顾Java基础知识,这次决定解决这个心头之痛。经过我的实现和学习,发现其实这个知识并不是很难。为了防止以后可能会有遗忘,就将我所了解的东西记录在这里。那么开始吧。
异常处理机制
Java其实实现了C++风格的异常处理,往往程序难免会出现一些异常,有些时候程序的异常会造成比较大的损失,因此就有了异常处理机制,能够对异常进行处理。
异常类
Java所有异常都是Throwable的子类,这也就是Java的一个异常类体系,这个必须了解清除。
这里需要解释一下Throwable的体系。
Throwable
所有的异常类都是Throwable的子类,其有两个主要的两个子类Error和Exception。
Error
Error类是程序运行出现非常严重错误,例如:VirtualMachineError
,OutOfMemoryError
和StackOverflowError
。这类错误一般不能通过程序的后续代码来解决,这是Java设计问题或者机器问题等因素导致程序无法执行。
这种错误可以通过try-catch捕捉到,但是无法利用代码来处理。
Exception
Expection
类又分为checked和unchecked。往往大部分可以通过程序代码就能解决的异常就是Exception
的子类。
checked Exception
可检测异常,也是一般写代码进行try-catch时最多出现的异常,IDE一般会要求进行异常捕捉,比如IOException
,SQLException
。
这类不会影响程序的运行,也是Java的设计者要求自己的程序去处理的异常。这类异常容易手动诊断与解决修复。因此为保证程序在即使出现此异常也能正常运行,需要捕捉并处理这些异常。
unchecked Excetion - RuntimeException
不可检测异常其实是指RuntimeException
(程序运行时异常)类。这类错误一般会影响程序的正常运行,例如我们知道的数组越界异常(ArrayIndexOutBoundsException
),遇到这类错误,程序会中断,在控制台中显示出来。所以并不是很需要将这类异常从catch中捕捉出来去处理。
详细包含的异常,可以自行查询API文档
异常处理方法
捕获并处理异常
try-catch-finally语句
1 | try{ |
需要注意的是:
- finally无论什么情况都会执行,所以往往用于执行最终的执行语句、
- finally中的
return
会覆盖原先的return
- finally 是可以省略的
- catch可以有多个,最靠前的catch最先进行捕捉,一旦捕捉到就不执行后面的其他catch语句了
- try语句后必须至少有一个catch或者finally
- try-catch-finally的块之间不能出现其他东西,这几个快区域必须紧凑连接,就好比if-else一样的关系
- catch中的参数可以是Exception类或者其子类的实例,但一般不建议使用
Exception
作为参数(Exception
的实例作为参数相当于任何异常都会捕捉到),最好具体情况具体处理 - catch的参数最好是checked的异常,因为
RuntimeException
一般虚拟机会负责报错。而且RuntimeException
会将程序终端,执行捕捉也不能将其处理
方法抛出异常
声明异常
在方法中使用throws
处理可能抛出的异常。
例子:
1 | public void bank () throws Exception,...{ //这里的异常类也是同理 |
需要注意:
throws
后面可以接多个异常类- 这是一种可能抛出异常的声明,如果有异常catch会捕捉到,如果方法没有此异常,则不会抛出异常
抛出异常
抛出异常出现在方法语句中,是一种手动抛出异常的手段,而且执行到throw
必定抛出异常。
例子:
1 | public void bank(){ |
注意:
throw
抛出的是异常类的实例对象,可以被catch捕捉到- 执行到
throw
必定抛出异常,程序会中断,而且其后面的语句也将不会执行,所以一般不会允许throw
后面紧跟任何代码 - 抛出异常一般是开发者知道在某个确定的情况必定会异常从而使用的。所以一般会在某个判断语句中,出现
throw
的使用。 - 如果是非自定义的异常类,包含
throw
的方法可以不声明异常(可以不使用throws),用上也可以,使得程序更严谨
自定义异常类
有的时候我们希望程序抛出我们自定的异常来进行处理,这时候可以使用自定义异常类。
Java机制只能处理Throwable的子类,因此自定义异常类也必须成为Throwable子类。
自定义异常类如果继承Exception
默认是指checked异常,继承RuntimeException
则是运行时异常。
例子:
1 | class GetMuchMoneyException extends Exception{ |
注意:
- 继承
Exception
默认是指checked异常,继承RuntimeException
则是运行时异常。 - 内部可以根据自己的使用自由定义需要的方法和成员变量
自定义异常类的使用
例如:
1 | //此方法可能会抛出异常 |
注意:
- 对于自定义异常类,可能抛出异常的方法必须同时声明异常和抛出异常(也就是
throws
和throw
同时共同使用)
小技巧
- try-catch 不光只能在main中使用,一些方法中可以嵌套使用。
- 不要再main中声明异常或者抛出异常
- 异常处理机制是会向上寻找解决办法。
- 我们甚至可以在接口的抽象方法中声明异常
1
2
3
4interface FileToServer{
...
public void GetFile()throws IOException;
}