异常处理干嘛的,重要吗?
重要。试想一下,你在面试的过程中,面试官问你一个问题,而恰好你忘了这个问题的解决方法,于是当你回答“这个不太清楚…但我有另外的思路要…”,还没等你说完,面试官就说“下一位!”。此时相信你是奔溃的哈。但这种面试官明显是不理智的,因为即是一个问题回答不上来,但他的综合素质很有可能就是你要找的“special one”。类比到JAVA语言中,如果系统并没有处理“一定”错误的能力,反而把最简单的异常都报送给程序员处理,那么这种工作量负担下程序员的寿命至少减10年…
于是聪明的程序员就把最常见的问题归类,并编写一定的解决方法,给JVM(类似于JAVA的运行环境)自己搞定。
异常的处理机制
- 发现异常
异常是指程序在运行过程中发生由于算法考虑不周或者软件设计错误等导致的程序异常事件。在JAVA中,所有的异常都是以类的形式存在的。所以JAVA发现异常的途径是“匹配”已定义的异常类,并生成异常对象。 - 抛出异常
生成异常对象并把它提交给运行系统的过程称为抛出异常。 - 捕获异常
当程序中抛出一个异常后,程序从程序中导致异常的代码处跳出,java虚拟机检测寻找和try关键字匹配的处理该异常的catch块,如果找到,将控制权交到catch块中的代码,然后继续往下执行程序,try块中发生异常的代码不会被重新执行。如果没有找到处理该异常的catch块,在所有的finally块代码被执行和当前线程的所属的ThreadGroup的uncaughtException方法被调用后,遇到异常的,当前线程被中止。
捕获异常的写法
try…catch…[finally]
try{
//可能出异常的代码
} catch(异常类 对象){
//处理该异常类型的语句
}
[finally] {
//一定会执行的代码
//catch块使用System.exit(1);除外
}
NOTE:
当try语句块出现异常,程序会自动跳到catch语句块去找匹配的异常类型,并执行异常处理语句,finally语句块是异常的统一出口。
一旦捕获到异常,处理完异常不会退回来接着执行try块的下一行代码,但会继续执行try-catch-finally块之后的语句
抛出异常的写法
throw/throws
由于当前方法不知道如何处理这种异常,可以使用throw/throws方法交给上一级调用者来处理。
1.throws(更常用)
格式:[修饰符] 返回值类型 方法名([参数列表]) throws 异常类列表
- 在方法“头部”声明以抛出可能出现异常的“类型”,如throws NullPointerException.
- 方法一旦采用了throws声明抛出方法内可能出现的异常类型,该方法就可以不再过问该异常了.
- 一个方法调用另一个使用throws声明抛出的方法,要么自己try…catch,要么也throws。这样可以一层一层的向上追溯,一直可追溯到main()方法,这时如果JVM能够有系统自身定义的方法处理,则能通过编译,否则会出现错误。
2.throw(系统一般会自动执行)
格式:throw 由异常类所产生的对象
- 在“方法体内”声明以抛出可能出现异常的“对象”
- 程序可以显示使用try…catch来捕获并处理,也可以不管,直接交给方法调用者处理
异常处理有哪些类
DEFINE
在“异常”类层次上的最上层有一个单独的类叫作Throwable,它是java.lang包中的一个类。这个类用来表示所有的异常情况。该类派生了两个子类java.lang.Error和java.lang.Exception。其中Error子类由系统保留,因为该类定义了那些应用程序通常无法捕捉到的错误。Error类及其子类的对象,代表了程序运行时Java系统内部的错误。即Error类及子类的对象是由Java虚拟机生成并抛出给系统,这种错误有内存溢出错、栈溢出错、动态链接错等。通常java程序不对这种错误进行直接处理,必须交由操作系统处理;而Exception子类则是供应用程序使用的,它是用户程序能够捕捉到的异常情况。一般情况下,通过产生它的子类来创建自己的异常,即Exception类对象是Java程序抛出和处理的对象,它有各种不同的子类分别对应于各种不同类型的异常。由于应用程序不处理Error类,所以一般所说的异常都是指Exception类及其子类。
《Java程序设计基础》
NOTE:
- Exception类从父类Throwable那里还继承了若干方法,最常用的有如下两个:
public String toString()
,该方法返回描述当前Exception类信息的字符串public void printStackTrace()
,该方法返回描述当前Exception类信息的字符串
- 在Exception类中有一个子类RuntimeException代表运行时异常,它是程序运行时自动地对某些错误做出反应而产生的,所以RuntimeException可以不编写异常处理的程序代码,依然可以成功编译,因为它是在程序运行时才有可能产生,如除数为0异常、数组下标越界异常、空指针异常等。这类异常应通过程序调试尽量避免不是使用try-catch-finally语句去捕获它。
- 除RuntimeException之外,其他则是非运行时异常,这种异常经常是在程序运行过程中由环境原因造成的异常,如输入输出异常、网络地址不能打开、文件未找到等。这类异常必须在程序中使用try-catch-finally语句去捕获它并进行相应的处理,否则不能通过编译。这是因为Java编译器要求Java程序必须捕捉或声明所有的非运行时异常,如果程序不加以捕捉,Java编译器则给出编译错误信息。
SUMMARY
程序对错误和异常的处理方式有三种
- 程序不能处理的错误
- 程序应避免而可以不去捕获的运行时异常
- 必须捕获的非运行时异常
异常的读法
e.printStackTrack()这类方法可以打印异常的堆栈信息,堆栈信息能够提供出现异常时的API调用顺序,这对于判断异常时如何出现的具有重大意义
例如
java.lang.StringIndexOutOfBoundsException: String index out of range: 9
at java.lang.StringBuffer.charAt(Unknown Source)
at PrintStack.main(PrintStack.java:13)
堆栈信息的读取应该这样:
– 从下到上,是方法调用的顺序,以上面的例子为例,首先调用的是PrintStack.main,在其第13行,
调用了StringBuffer.charAt(),这个方法触发了上述的异常,
– 有了这个信息,就可以很快的判断在调用StringBuffer.charAt()时需要做范围的判断,防止越界
总结
异常处理是各项事务(不仅仅是编程)中的一种重要的思想——-应对“突发情况”的处理模式。
之后关于异常的学习应该是去总结具体的例子了