异常处理(try.catch.finally 与 throw.throws )
我们为什么需要异常处理?
既然知道程序有出现异常的可能,为了系统可以长期稳定的运行,那就务必得事先规避已知的异常。做到“知错就改”,这一点毋庸置疑吧。
异常的处理,分为两种:1.通过try.catch.finally捕获异常。2.通过throw.throws声明抛出异常。
try.catch.finally
try、catch与finally,这是Java中的三个关键字,它们常连起来用,来实现对异常的捕获及处理。大致过程可以描述为:
用try来执行一段程序,如果出现异常,系统抛出一个异常,可以通过它的类型来捕捉(catch)并处理它,最后一步是通过finally语句为异常处理提供一个统一的出口,finally所指定的代码都要被执行(catch语句可有多条;finally语句最多只能有一条,根据自己的需要可有可无)。来个代码模板:
try {
可能有异常的语句、代码块;
}catch(Exception1 e) {
}catch(Exception2 e) {
}finally {
}
注意点
在使用try.catch.finally时需要注意的关键点:
- 在try中的代码块,如果遇到了异常,则立马开始进行异常捕获处理,try中异常代码后的语句将不会继续执行,异常处理完成后也不会回到try继续执行。
- 一个try语句必须带有至少一个catch语句块或一个finally语句块 。
- try语句块可以伴随一个或多个catch语句,实现多重捕获。
- 多重捕获时,应该先把子类异常放前,父类异常在后。因为子类异常会被父类捕获,如果被在前的父类异常捕获后,则不再会被在后的子类异常捕获。
- finally中的语句,不管是否发生异常,都会执行。即使try和catch块中存在return语句,finally语句也会执行。
- 通常在finally中关闭程序块已打开的资源,比如:关闭文件流、释放数据库连接等。
- finally语句块只有一种情况是不会执行的,那就是在执行finally之前遇到了程序结束,如:System.exit(0)。
常用方法
catch捕获异常后,有一些常用的方法,这些方法均继承自Throwable类 :
- toString ()方法,显示异常的类名和产生异常的原因
- getMessage()方法,只显示产生异常的原因,但不显示类名。
- printStackTrace()方法,用来跟踪异常事件发生时堆栈的内容。
throw.throws
我经常在所谓的面试合计博客中,看见如“throw与throws关键字的区别是什么?、final关键字与finally关键字的区别是什么?”这类问题,我觉得这种问题应该只有在校招时才会问吧。
对于关键字,我们不应该只看它的字母、单词,而是应该注意它的实际用法,我们为什么需要这个关键字等问题上。在编程中,所有的字母与单词都只是一个符号,就算如果有一天Java把throw换了一种名称,但只要设计的目的与作用一样,它就是同一种东西,不要被“咬文嚼字”带偏了。
好了,回到我们的主题:throw与throws。有一些情况下的异常,我们并不需要在当前就立马处理它们。比如你做了一个底层功能,被上游调用时调用的过程有问题,此时的异常就不该你处理,而是需要向上传递给调用它的方法处理。
throw
我们可以使用throw关键字,来手动抛出异常:
public void test(int a) throws Exception {
throw new Exception(); // 通过throw手动抛出异常
}
throws
如果一个方法或类中可能产生某种异常,但是并没有进行try.catch.finally捕获处理,则应在方法或类的首部,用声明throws该方法或类可能抛出异常及异常类型。
public class Test {
public static void main(String[] args) throws Exception{ //调用test方法时可能有异常,但未捕获
test(1);
}
public static void test(int a) throws Exception { // test方法,方法内有抛出异常,但未捕获
System.out.println(a);
throw new Exception();
}
}
也就是说,一个异常的终点,就是被捕获。当被捕获后,再往上则没有该异常了。
使用throws上抛异常时,如果有多个异常类型,中间用 “ , ” 隔开,并且可以声明未异常类型的父类。