Java核心技术读书笔记7-1 Java异常
1.异常
1.1 处理错误
异常处理的任务就是将控制源从错误产生的地方转移给能够处理这种情况的错误处理器。
1.2 异常分类
在Java中,所有异常对象都是派生于Throwable类的一个实例。

对于Throwable类的两个子类:
Error类:描述了Java运行时系统内部错误和资源耗尽错误。应用程序不应该抛出这种类型的对象。所以若出现这种内部错误,除了告知用户并尽力使程序安全终止别无他法。
Exception类:需要关注这类错误,对于其两个子类,RuntimeException类表示了由程序错误导致的问题(出现这种问题一定是你程序编写的问题),IOException则描述了I/O相关错误。
Java将派生于Error类或RuntimeException类的所有异常称为非受查异常,其它异常称为受查异常。编译器将检查是否为所有受查异常提供了异常处理器。换言之非受查异常是你能控制的正常情况不应该发生的异常,受查异常才是程序应该检查处理的。
1.3 创建一个自己的异常类:如果系统中的异常都无法满足描述自己代码中出现异常的场景,那么就可以自己构建一个异常类,然后用该类继承一个异常类。
public class MyException extends RuntimeException{
public MyException(){
new MyException("");
}
public MyException(String message){
super(message);
System.out.println("-----myException-----");
}
}
1.4 异常声明与处理
—抛出异常:一个方法不仅要告诉编译器返回什么值,还要告诉编译器可能发生什么错误。
throws关键字:对于方法可能会出现的受查异常,可以用throws关键字对其进行抛出告知编译器并交给调用者处理。这是系统便会搜索对应的异常处理器,以便知道如何处理异常对象。若有多个异常抛出则使用逗号分隔。若子类覆盖了超类的一个方法,子类方法中声明的受查异常不能比超类方法总声明的异常更通用(即子类应该更明确的抛出某种特定的异常),所以如果超类没有抛出异常,子类一不应该抛出异常。
public void aMethod(parameters..) throws ExceptionA, ExceptionB
throw关键字:如果我们想在代码抛出一个指定的异常可以使用该关键字。抛出后需要在方法后使用throws声明抛出的异常。
public class ThrowTest {
public void testMethod() throws RuntimeException { //声明的异常必须大于等于实际抛出异常的级别
boolean flag;
System.out.println("do something...");
flag = false; //some things are not normal
System.out.println("If something goes wrong, I want to throw an exception");
if(!flag){
throw new MyException("flag = " + flag + " means Some things are not normal"); //括号内可以传入一个字符串信息
}
}
public static void main(String[] args) throws Exception {
new ThrowTest().testMethod();
}
}

—捕获异常:有些代码必须捕获异常,然后对异常进行处理。如果异常发生是没有在任何地方进行捕获,那么程序就会终止执行,并在控制台打印出异常信息,包括异常的类型和堆栈信息。
try/catch
try{
codes..
}
catch(ExceptiohType e)
{
handler for this type
}
若try语句块中没有抛出任何异常,则跳过catch子句;
若try语句块中任何代码抛出了一个在catch子句中说明的异常类,那么:
1)跳过try语句块中其余代码
2)执行catch子句中的代码
若try语句块中代码抛出了一个在catch子句中没有说明的异常类,那么方法立刻退出。
抛出or捕获? 应该捕获那些知道如何处理的异常,将不知道怎样处理的异常继续进行传递。但若出现超类没抛出异常这种情况,则子类必须捕获每一个可能出现的异常。
捕获多个异常:若程序可能出现多个异常,且不同异常的处理方式也可能不同,那么应按照从低到高的顺序依次书写catch子句进行捕获(否则,若将最高级别异常catch放到最上面,则只要出现任何低于该级别的异常将会都被该句捕获)。
try{
codes..
}
catch(最低级别异常类型 e)
{
handler for this type
}
catch(相同处理方式异常类型1| 相同处理方式异常类型2 e) //相同处理类型的异常可以写到一个catch中,异常类型用"|"分隔
{
handler for this type
}
catch(可能出现的最高级别异常 e)
{
handler for this type
}
捕获多个异常变量时,该变量隐含final属性,不可更改其值
捕获异常重新抛出:重新抛出的目的是为了改变异常类型
try{
boolean flag;
System.out.println("do something...");
flag = false; //some things are not normal
System.out.println("If something goes wrong, I want to throw an exception");
if(!flag){
throw new MyException("flag = " + flag + " means Some things are not normal"); //括号内可以传入一个字符串信息
}
}catch (MyException e){
// e.printStackTrace(); //打印异常的堆栈信息
// throw new RuntimeException("产生了一个自定义异常 " + e.getMessage()); //使用一个异常文本构造: 产生了一个自定义异常 flag = false means Some things are not normal
Exception se = new RuntimeException("产生了自定义异常"); //更高级的方法,可以抛出一个高级异常,但不会丢原异常的细节
se.initCause(e);
throw se;
}
finally子句:若代码抛出了一个异常,就会终止方法中剩余代码的处理并退出方法。若方法获得了一些本地资源,那么这些资源应该方法退出之前被回收。此时,若果出现异常就产生了资源回收问题。
InputStream is = new FileInputStream(..);
try
{
...
}catch(IOException e) //try语句可以只有finally子句而没有catch子句
{
...
}finally{
in.close;
}
对于异常抛出和finally语句有两个原则:
1)finally块内的语句一定会在所在语句块(try/catch)的最后执行(含有return除外),无论是否出现异常以及异常是否继续抛出。
2)若当前块中代码出现异常,则当前块其余代码立即终止执行并抛出异常。抛出的异常交由本层代码块的catch子句处理否则向外层传递。
那么若果catch语句中有return语句且未发生异常的情况下该怎么办呢?
1)若finally块中同样含有return语句,则finally中的return覆盖catch中的return。
2)否则,catch中return会在finally语句块代码执行完毕后执行。
带资源的try语句(try-with-resorces)
try(Resource res = ...)
{
...
}
该语句在java7引入,括号中使用的资源变量所属的类需要实现AutoCloseable接口,该接口包含一个可以抛出Exception异常的close()方法(另有一个Closeable接口,抛出的是IOException),多个资源有分号;隔开。
该语句相当于实现了一个finally结构,括号中的资源会无论会不会发生异常都会关闭,同时对于关闭资源可能会产生的异常也有很好的处理。若关闭失败则抛出异常,若try语句块中与close都出现异常并抛出,则会把close抛出的异常抑制,然后使用addSuppressed(Throwable t)方法增加到原来的异常,而原来的异常会正常抛出。
Throwable[] getSuppressed();可以得到调用异常对象的所有被抑制异常。
1.5 堆栈轨迹(stack trace):是一个方法调用过程的列表,包含了程序执行过程中方法调用的特定位置。下面为获取方法:
Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces(); //获取所有线程的堆栈轨迹映射。key为线程,value对应线程的堆栈元素数组
new Throwable().getStackTrace(); //获取堆栈元素数组
new Throwable.printStackTrace([A outStream]); //打印堆栈信息到一个输出流中,如无输出流参数则默认输出到标准错误输出流System.err中。
对于堆栈元素,可以使用如下方法获取信息:

浙公网安备 33010602011771号