4.6.0——try,catch,finally的执行机制
1.catch块和finally块至少要有一个
2.关于return
我们知道try块在返回之前,会将返回值存储在一个指定位置,然后再去执行finally,等执行完finally块,才会将返回值返回。但是如果finally块中有return,那么这个return将会覆盖其他return语句。
3.有try,catch,finally机制我们知道,如果finally中没有return语句,那么返回值在进入finally块之前就已经是确定的了,那么无论finally块中如何修改这个值,返回值也不会改变。但是同样的也要考虑返回值和返回引用的区别,比如是一个引用类型,那么finally块中修改会影响返回的结果
4.6.1——finally块中的代码是不是一定会执行
1.在java语言的异常处理中,finally块的作用就是为了保证无论发生什么情况,finally块里的代码总是会被执行。那有没有什么情况是finally块不一定会执行的情况呢?有两种情况
1)
int i = 5/0;
try{}….
程序在int i = 5/0时会抛出异常,导致没有执行try块,因此finally块也没有执行
2)
Try{
System.out.println(“try block”);
System.exit(0);
}
程序在try块中通过调用System.exit(0)强制退出了程序,因此导致finally块中的代码没有被执行
4.6.2——异常处理的原理是什么?
1.首先java把异常当作对象来处理,并且定义了一个基类Throwable(可抛出的)作为所有异常的父类,这个基类有两个子类:Error(错误)和Exception(异常)两个大类。异常这个概念是指程序运行时(非编译时)所发生的非正常的情况或者错误时,jvm就会将出现的错误表示为一个异常并抛出
2.Error表示程序在运行期间出现了严重的错误,并且这种错误是不可以恢复的,由于这属于jvm层次的错误,因此这种错误会导致程序终止执行。此外编译器不会检查Error是否被处理,因此在程序中不推荐去捕获Error类的异常,主要原因是Error类的异常多是由于逻辑错误导致的,属于应该解决的错误,也就是说,一个正确的程序是不应该存在Error的。比如OutOfMemoryError,ThreadDeath等都属于错误,当这些异常发生的时候,jvm一般选择将线程中止。
3.Exception表示可恢复的异常,是编译器可以捕捉到的,它又包含两种:checked exception(检查异常)和runtime exception(运行时异常),注意这里不是类的名称,而是子类的特征。
1)checked exception是程序中最常见的异常,所有继承自Exception并且不是运行时异常的异常都是checked exception,比如常见的IO异常和SQL异常。这种异常都发生在编译阶段,java编译器强制程序去捕获此类型的异常,即将可能会出现这些异常的代码放入try块中,把对异常处理的代码放入catch块中,这种异常一般发生在如下几种情况
A.异常的发生并不会导致程序出错,进行处理后可以继续执行后续的操作,例如,当连接数据库失败后,可以重新连接后进行后续操作
B.程序依赖不可靠的外部条件
2)runtime exception运行时异常不同于checked exception检查异常,编译器没有强制对其进行捕获并处理,如果不对这种异常进行处理,当出现这种异常的时候,会由jvm来处理。在java语言中,最常见的异常包括
NullPointerException(空指针异常)
ClassCastException(类型转换异常)
ArrayIndexOfBoundsExceprion(数组越界异常)
ArrayStoreException(数组存储异常)
BufferOverflowException(缓冲区溢出异常)
ArithmeticException(算术异常)
出现运行时异常的时候,系统会把异常一直往上层抛出,知道遇到处理代码为止,若没有处理块,就抛到最上层,如果是多线程就用Thread.run()方法抛出,如果是单线程就用main()方法抛出。抛出之后,如果是线程,那么这个线程也就退出了,如果是主程序抛出的异常,那么整个程序也就中止了,所以如果不对运行时的异常进行处理,后果很严重,一旦发生问题,要么是线程中止,要么是主程序中止。
3)java异常处理中用到了多态的概念,如果在异常处理中,先捕获了基类,再捕获子类,那么捕获子类的代码永远不会被执行,因此,在进行一场捕获时,正确的写法是先捕获子类,在捕获基类的异常信息
如:
Try{
//
}catch(SQLException e1){
}catch(Exception)
4)尽早抛出异常,同时对捕获的异常进行处理,或者从故障中恢复,或者让程序继续执行,对捕获的异常不进行任何处理是一个非常不好的习惯,这样将非常不利于调试,但是也不是抛出的异常越多越好,对于有些异常,如运行时异常,实际上根本不必处理
5)可以根据实际的需求定义异常类,这些自定义的异常类自要继承自Exception类即可
异常能处理就处理,不能处理就抛出,对于一般异常,如果不能进行行之有效的处理,最好转换为运行时异常抛出,对于最终没有处理的异常,jvm会进行处理。