java知识总结——异常处理
说明
本文仅仅为了博主面试时方便查阅与梳理相关知识,如果有错误与不到位的地方,欢迎大佬指点改正,谢谢!
阅读书籍:《java程序员面试笔试宝典》
一、finally块中的代码什么时候被执行
在java语言的异常处理中,finally块的作用就是为了保证无论出现什么情况,finally块里的代码一定会执行。
由于程序执行return就意味着结束对当前函数的调用并跳出这个函数体,因此任何语句要执行都只能在return前执行,因此finally块里的代码也是在return前执行的,如果finally中有return语句,那么返回的一定是finally中return的值。
注意:当finally块中有return语句时,将会覆盖函数中其他return语句。
由于在一个方法内部定义的变量都存储在栈中,当这个函数结束后,其对应的栈就会被回收,此时在其方法体中定义的变量将不存在了,因此return在返回时不是直接返回变量的值,而是复制一份,然后返回。因此,
对于基本类型的数据,在finally块中改变return的值对返回值没有影响,而对引用类型的数据有影响。
出现在java程序中的finally块中是不是一定会被执行?
不一定会被执行。
第一种情况:当程序在进入try语句块之前就出现异常时,会直接结束,不会执行finally块中的代码。
第二章情况:当程序在try块中强制退出时(System.exit(0))也不会去执行finally块中的代码。
二、异常处理的原理
异常是指程序运行时(非编译时)所发生的非正常情况或错误,当程序违反了语义规则时,JVM就会将出现的错误表示为一个异常并抛出。这个异常可以在catch程序块中进行捕获,然后进行处理。而异常处理的目的是为了提高程序的安全性和健壮性(鲁棒性)。
java语言把异常当做对象来处理,并定义了一个基类(java.lang.Throwable)作为所有异常的父类。
在java API中,已经定义了许多异常类,这些异常类分为Error(错误)和Exception(异常)两大类。
违反语义的两种情况:
第一种是java类库内置的语义检查;
第二种是java允许开发人员扩展这种语义检查,开发人员可以创建自己的异常类(所有一次都是java.lang,Throwable的子类),并自由选择在何时用throw关键字抛出异常。
三、运行时异常和普通异常
java提供了两种错误的异常类,分别为Error和Exception,且它们拥有共同的父类——Throwable。
1、Error
Error表示程序在运行期间出现了非常严重的错误,并且该错误是不可恢复的,由于JVM层次的严重错误,因此这种错误是会导致程序终止执行的。
2、Exception
Exception表示可恢复的异常,是编译器可以捕捉到的。它包含两种异常:检查异常(checked exception)和运行时异常(runtime exception)。
(1)检查异常(checked exception)
检查异常是在程序中最常见的异常。所有继承自Exception并且不是运行时异常的异常都是检查异常。这种异常都发生在编译阶段,java编译器强制程序去捕获此类型的异常,即把可能会出现这些异常的代码放到try块中,把对异常的处理代码放在catch块中。
检查异常在以下情况中使用:
①异常的发生并不会导致程序出错,进行处理后继续执行后续的操作。
②程序依赖于不可靠的外部条件。
(2)运行时异常(runtime exception)
编辑器没有强制对运行时异常进行捕获并处理,如果不对这种异常进行处理,当出现这种异常时,会由JVM来处理。
出现运行时异常时,系统会把异常一直往上层抛出,直到遇到处理代码为止。若没有处理代码,则抛到最上层。
如果是多线程就用Thread.run()方法抛出,如果是单线程,就用main()方法抛出。
如果是线程,那么线程退出;如果是主程序,那么主程序退出。
在异常处理中需要注意的几个问题:
①java异常处理用到了多态的概念,如果在异常处理过程中,先捕获了基类,然后再捕获子类,那么捕获子类的代码块将永远不会被执行。因此,在进行异常捕获时,正确的写法是:先捕获子类,子再捕获基类的异常信息。
②尽早抛出异常,同时对捕获的异常进行处理,或者从错误中恢复,或者让程序继续执行。
③可以根据实际的需求自定义异常类,这些自定义的异常类只要继承自Exception类即可。
④异常能处理就处理,不能处理就抛出。对于一般的异常,如果不能进行行之有效的处理,最好转换为运行时异常抛出。对于最终没有处理的异常,JVM会进行处理。