首页 > 代码库 > java异常处理
java异常处理
Java异常处理总结
异常处理是程序设计中一个很重要的方面,也是程序设计的一大难点,从C開始,你或许已经知道怎样用if...else...来控制异常了,或许是自发的,然而这样的控制异常痛苦,同一个异常或者错误假设多个地方出现,那么你每一个地方都要做同样处理,感觉相当的麻烦!
Java语言在设计的当初就考虑到这些问题,提出异常处理的框架的方案,全部的异常都能够用一个类型来表示,不同类型的异常相应不同的子类异常(这里的异常包含错误概念),定义异常处理的规范,在1.4版本号以后添加了异常链机制,从而便于跟踪异常!这是Java语言设计者的高明之处,也是Java语言中的一个难点,以下是我对Java异常知识的一个总结,也算是资源回收一下。
一、Java异常的基础知识
异常是程序中的一些错误,但并非全部的错误都是异常,而且错误有时候是能够避免的。比方说,你的代码少了一个分号,那么执行出来结果是提示是错误java.lang.Error;假设你用System.out.println(11/0),那么你是由于你用0做了除数,会抛出java.lang.ArithmeticException的异常。
有些异常须要做处理,有些则不须要捕获处理,后面会具体讲到。
天有不測风云,人有旦夕祸福,Java的程序代码也如此。在编程过程中,首先应当尽可能去避免错误和异常发生,对于不可避免、不可预測的情况则在考虑异常发生时怎样处理。
Java中的异经常使用对象来表示。Java对异常的处理是按异常分类处理的,不同异常有不同的分类,每种异常都相应一个类型(class),每一个异常都相应一个异常(类的)对象。
异常类从哪里来?有两个来源,一是Java语言本身定义的一些基本异常类型,二是用户通过继承Exception类或者其子类自定义的异常。Exception 类及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件。
异常的对象从哪里来呢?有两个来源,一是Java执行时环境自己主动抛出系统生成的异常,而无论你是否愿意捕获和处理,它总要被抛出!比方除数为0的异常。二是程序猿自己抛出的异常,这个异常能够是程序猿自定义的,也能够是Java语言中定义的,用throw keyword抛出异常,这样的异经常常使用来向调用者汇报异常的一些信息。
异常是针对方法来说的,抛出、声明抛出、捕获和处理异常都是在方法中进行的。
Java异常处理通过5个keywordtry、catch、throw、throws、finally进行管理。基本过程是用try语句块包住要监视的语句,假设在try语句块内出现异常,则异常会被抛出,你的代码在catch语句块中能够捕获到这个异常并做处理;还有以部分系统生成的异常在Java运行时自己主动抛出。你也能够通过throwskeyword在方法上声明该方法要抛出异常,然后在方法内部通过throw抛出异常对象。finally语句块会在方法运行return之前运行,一般结构例如以下:
try{
程序代码
}catch(异常类型1 异常的变量名1){
程序代码
}catch(异常类型2 异常的变量名2){
程序代码
}finally{
程序代码
}
try{
程序代码
}catch(异常类型1 异常的变量名1){
程序代码
}catch(异常类型2 异常的变量名2){
程序代码
}finally{
程序代码
}
catch语句能够有多个,用来匹配多个异常,匹配上多个中一个后,运行catch语句块时候只运行匹配上的异常。catch的类型是Java语言中定义的或者程序猿自定义的,表示代码抛出异常的类型,异常的变量名表示抛出异常的对象的引用,假设catch捕获并匹配上了该异常,那么就能够直接用这个异常变量名,此时该异常变量名指向所匹配的异常,而且在catch代码块中能够直接引用。这一点很很的特殊和重要!
Java异常处理的目的是提高程序的健壮性,你能够在catch和finally代码块中给程序一个修正机会,使得程序不因异常而终止或者流程发生以外的改变。同一时候,通过获取Java异常信息,也为程序的开发维护提供了方便,一般通过异常信息就非常快就能找到出现异常的问题(代码)所在。
Java异常处理是Java语言的一大特色,也是个难点,掌握异常处理能够让写的代码更健壮和易于维护。
二、Java异常类类图
以下是这几个类的层次图:
java.lang.Object
java.lang.Throwable
java.lang.Exception
java.lang.RuntimeException
java.lang.Error
java.lang.ThreadDeath
java.lang.Object
java.lang.Throwable
java.lang.Exception
java.lang.RuntimeException
java.lang.Error
java.lang.ThreadDeath
以下四个类的介绍来自java api 文档。
1、Throwable
Throwable 类是 Java 语言中全部错误或异常的超类。仅仅有当对象是此类(或其子类之中的一个)的实例时,才干通过 Java 虚拟机或者 Java throw 语句抛出。类似地,仅仅有此类或其子类之中的一个才干够是 catch 子句中的參数类型。
Throwable 类是 Java 语言中全部错误或异常的超类。仅仅有当对象是此类(或其子类之中的一个)的实例时,才干通过 Java 虚拟机或者 Java throw 语句抛出。类似地,仅仅有此类或其子类之中的一个才干够是 catch 子句中的參数类型。
两个子类的实例,Error 和 Exception,通经常使用于指示发生了异常情况。通常,这些实例是在异常情况的上下文中新近创建的,因此包括了相关的信息(比方堆栈跟踪数据)。
2、Exception
Exception 类及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件,表示程序本身能够处理的异常。
Exception 类及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件,表示程序本身能够处理的异常。
3、Error
Error 是 Throwable 的子类,表示仅靠程序本身无法恢复的严重错误,用于指示合理的应用程序不应该试图捕获的严重问题。
Error 是 Throwable 的子类,表示仅靠程序本身无法恢复的严重错误,用于指示合理的应用程序不应该试图捕获的严重问题。
在运行该方法期间,无需在方法中通过throws声明可能抛出但没有捕获的 Error 的不论什么子类,由于Java编译器不去检查它,也就是说,当程序中可能出现这类异常时,即使没实用try...catch语句捕获它,也没实用throws字句声明抛出它,还是会编译通过。
4、RuntimeException
RuntimeException 是那些可能在 Java 虚拟机正常执行期间抛出的异常的超类。Java编译器不去检查它,也就是说,当程序中可能出现这类异常时,即使没实用try...catch语句捕获它,也没实用throws字句声明抛出它,还是会编译通过,这样的异常能够通过改进代码实现来避免。
RuntimeException 是那些可能在 Java 虚拟机正常执行期间抛出的异常的超类。Java编译器不去检查它,也就是说,当程序中可能出现这类异常时,即使没实用try...catch语句捕获它,也没实用throws字句声明抛出它,还是会编译通过,这样的异常能够通过改进代码实现来避免。
5、ThreadDeath
调用 Thread 类中带有零參数的 stop 方法时,受害线程将抛出一个 ThreadDeath 实例。
调用 Thread 类中带有零參数的 stop 方法时,受害线程将抛出一个 ThreadDeath 实例。
仅当应用程序在被异步终止后必须清除时才应该捕获这个类的实例。假设 ThreadDeath 被一个方法捕获,那么将它又一次抛出很重要,由于这样才干让该线程真正终止。
假设没有捕获 ThreadDeath,则顶级错误处理程序不会输出消息。
尽管 ThreadDeath 类是“正常出现”的,但它仅仅能是 Error 的子类而不是 Exception 的子类,由于很多应用程序捕获全部出现的 Exception,然后又将其放弃。
以上是对有关异常API的一个简介,使用方法都非常easy,关键在于理解异常处理的原理,详细使用方法參看Java API文档。
三、Java异常处理机制
对于可能出现异常的代码,有两种处理办法:
第一、在方法中用try...catch语句捕获并处理异常,catach语句能够有多个,用来匹配多个异常。比如:
public void p(int x){
try{
...
}catch(Exception e){
...
}finally{
...
}
}
第二、对于处理不了的异常或者要转型的异常,在方法的声明处通过throws语句抛出异常。比如:
public void test1() throws MyException{
...
if(....){
throw new MyException();
}
}
...
if(....){
throw new MyException();
}
}
假设每一个方法都是简单的抛出异常,那么在方法调用方法的多层嵌套调用中,Java虚拟机会从出现异常的方法代码块中往回找,直到找到处理该异常的代码块为止。然后将异常交给对应的catch语句处理。假设Java虚拟机追溯到方法调用栈最底部main()方法时,假设仍然没有找到处理异常的代码块,将依照以下的步骤处理:
第一、调用异常的对象的printStackTrace()方法,打印方法调用栈的异常信息。
第二、假设出现异常的线程为主线程,则整个程序执行终止;假设非主线程,则终止该线程,其它线程继续执行。
第一、调用异常的对象的printStackTrace()方法,打印方法调用栈的异常信息。
第二、假设出现异常的线程为主线程,则整个程序执行终止;假设非主线程,则终止该线程,其它线程继续执行。
通过分析思考能够看出,越早处理异常消耗的资源和时间越小,产生影响的范围也越小。因此,不要把自己能处理的异常也抛给调用者。
另一点,不可忽视:finally语句在不论什么情况下都必须运行的代码,这样能够保证一些在不论什么情况下都必须运行代码的可靠性。比方,在数据库查询异常的时候,应该释放JDBC连接等等。finally语句先于return语句运行,而不论其先后位置,也无论是否try块出现异常。finally语句唯一不被运行的情况是方法运行了System.exit()方法。System.exit()的作用是终止当前正在运行的 Java 虚拟机。finally语句块中不能通过给变量赋新值来改变return的返回值,也建议不要在finally块中使用return语句,没有意义还easy导致错误。
最后还应该注意一下异常处理的语法规则:
第一、try语句不能单独存在,能够和catch、finally组成 try...catch...finally、try...catch、try...finally三种结构,catch语句能够有一个或多个,finally语句最多一个,try、catch、finally这三个keyword均不能单独使用。
第一、try语句不能单独存在,能够和catch、finally组成 try...catch...finally、try...catch、try...finally三种结构,catch语句能够有一个或多个,finally语句最多一个,try、catch、finally这三个keyword均不能单独使用。
第二、try、catch、finally三个代码块中变量的作用域分别独立而不能相互訪问。假设要在三个块中都能够訪问,则须要将变量定义到这些块的外面。
第三、多个catch块时候,Java虚拟机会匹配当中一个异常类或其子类,就运行这个catch块,而不会再运行别的catch块。
第四、throw语句后不同意有紧跟其它语句,由于这些没有机会运行。
第五、假设一个方法调用了另外一个声明抛出异常的方法,那么这种方法要么处理异常,要么声明抛出。
那怎么推断一个方法可能会出现异常呢?一般来说,方法声明的时候用了throws语句,方法中有throw语句,方法调用的方法声明有throwskeyword。
throw和throwskeyword的差别
throw用来抛出一个异常,在方法体内。语法格式为:throw 异常对象。
throws用来声明方法可能会抛出什么异常,在方法名后,语法格式为:throws 异常类型1,异常类型2...异常类型n。
throw用来抛出一个异常,在方法体内。语法格式为:throw 异常对象。
throws用来声明方法可能会抛出什么异常,在方法名后,语法格式为:throws 异常类型1,异常类型2...异常类型n。
四、怎样定义和使用异常类
1、使用已有的异常类,假如为IOException、SQLException。
try{
程序代码
}catch(IOException ioe){
程序代码
}catch(SQLException sqle){
程序代码
}finally{
程序代码
}
程序代码
}catch(IOException ioe){
程序代码
}catch(SQLException sqle){
程序代码
}finally{
程序代码
}
2、自己定义异常类
创建Exception或者RuntimeException的子类就可以得到一个自己定义的异常类。比如:
public class MyException extends Exception{
public MyException(){}
public MyException(String smg){
super(smg);
}
}
创建Exception或者RuntimeException的子类就可以得到一个自己定义的异常类。比如:
public class MyException extends Exception{
public MyException(){}
public MyException(String smg){
super(smg);
}
}
3、使用自己定义的异常
用throws声明方法可能抛出自己定义的异常,并用throw语句在适当的地方抛出自己定义的异常。比如:
用throws声明方法可能抛出自己定义的异常,并用throw语句在适当的地方抛出自己定义的异常。比如:
在某种条件抛出异常
public void test1() throws MyException{
...
if(....){
throw new MyException();
}
}
public void test1() throws MyException{
...
if(....){
throw new MyException();
}
}
将异常转型(也叫转译),使得异常更易读易于理解
public void test2() throws MyException{
...
try{
...
}catch(SQLException e){
...
throw new MyException();
}
}
public void test2() throws MyException{
...
try{
...
}catch(SQLException e){
...
throw new MyException();
}
}
另一个代码,非常有意思:
public void test2() throws MyException{
...
try {
...
} catch (MyException e) {
throw e;
}
}
public void test2() throws MyException{
...
try {
...
} catch (MyException e) {
throw e;
}
}
这段代码实际上捕获了异常,然后又和盘托出,没有一点意义,假设这样还有什么优点理的,不处理即可了,直接在方法前用throws声明抛出不就得了。异常的捕获就要做一些有意义的处理。
五、执行时异常和受检查异常
Exception类能够分为两种:执行时异常和受检查异常。
1、执行时异常
RuntimeException类及其子类都被称为执行时异常,这样的异常的特点是Java编译器不去检查它,也就是说,当程序中可能出现这类异常时,即使没实用try...catch语句捕获它,也没实用throws字句声明抛出它,还是会编译通过。比如,当除数为零时,就会抛出java.lang.ArithmeticException异常。
2、受检查异常
除了RuntimeException类及其子类外,其它的Exception类及其子类都属于受检查异常,这样的异常的特点是要么用try...catch捕获处理,要么用throws语句声明抛出,否则编译不会通过。
除了RuntimeException类及其子类外,其它的Exception类及其子类都属于受检查异常,这样的异常的特点是要么用try...catch捕获处理,要么用throws语句声明抛出,否则编译不会通过。
3、两者的差别
执行时异常表示无法让程序恢复执行的异常,导致这样的异常的原因一般是因为执行了错误的操作。一旦出现错误,建议让程序终止。
受检查异常表示程序能够处理的异常。假设抛出异常的方法本身不处理或者不能处理它,那么方法的调用者就必须去处理该异常,否则调用会出错,连编译也无法通过。当然,这两种异常都是能够通过程序来捕获并处理的,比方除数为零的执行时异常:
执行时异常表示无法让程序恢复执行的异常,导致这样的异常的原因一般是因为执行了错误的操作。一旦出现错误,建议让程序终止。
受检查异常表示程序能够处理的异常。假设抛出异常的方法本身不处理或者不能处理它,那么方法的调用者就必须去处理该异常,否则调用会出错,连编译也无法通过。当然,这两种异常都是能够通过程序来捕获并处理的,比方除数为零的执行时异常:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!!!");
try{
System.out.println(1/0);
}catch(ArithmeticException e){
System.out.println("除数为0!");
}
System.out.println("除数为零后程序没有终止啊,呵呵!!!");
}
}
public static void main(String[] args) {
System.out.println("Hello World!!!");
try{
System.out.println(1/0);
}catch(ArithmeticException e){
System.out.println("除数为0!");
}
System.out.println("除数为零后程序没有终止啊,呵呵!!!");
}
}
执行结果:
Hello World!!!
除数为0!
除数为零后程序没有终止啊,呵呵!!!
4、执行时错误
Error类及其子类表示执行时错误,一般是由Java虚拟机抛出的,JDK中与定义了一些错误类,比方VirtualMachineError
和OutOfMemoryError,程序本身无法修复这些错误.一般不去扩展Error类来创建用户自己定义的错误类。而RuntimeException类表示程序代码中的错误,是可扩展的,用户能够创建特定执行时异常类。
Error(执行时错误)和执行时异常的同样之处是:Java编译器都不去检查它们,当程序执行时出现它们,都会终止执行。
Error类及其子类表示执行时错误,一般是由Java虚拟机抛出的,JDK中与定义了一些错误类,比方VirtualMachineError
和OutOfMemoryError,程序本身无法修复这些错误.一般不去扩展Error类来创建用户自己定义的错误类。而RuntimeException类表示程序代码中的错误,是可扩展的,用户能够创建特定执行时异常类。
Error(执行时错误)和执行时异常的同样之处是:Java编译器都不去检查它们,当程序执行时出现它们,都会终止执行。
5、最佳解决方式
对于执行时异常,我们不要用try...catch来捕获处理,而是在程序开发调试阶段,尽量去避免这样的异常,一旦发现该异常,正确的做法就会改进程序设计的代码和实现方式,改动程序中的错误,从而避免这样的异常。捕获并处理执行时异常是好的解决的方法,由于能够通过改进代码实现来避免该种异常的发生。
对于受检查异常,没说的,老老实实去依照异常处理的方法去处理,要么用try...catch捕获并解决,要么用throws抛出!
对于Error(执行时错误),不须要在程序中做不论什么处理,出现故障后,应该在程序在外的地方找问题,然后解决。
对于Error(执行时错误),不须要在程序中做不论什么处理,出现故障后,应该在程序在外的地方找问题,然后解决。
六、异常转型和异常链
异常转型在上面已经提到过了,实际上就是捕获到异常后,将异常以新的类型的异常再抛出,这样做一般为了异常的信息更直观!比方:
public void run() throws MyException{
...
try{
...
}catch(IOException e){
...
throw new MyException();
}finally{
...
}
}
public void run() throws MyException{
...
try{
...
}catch(IOException e){
...
throw new MyException();
}finally{
...
}
}
异常链,在JDK1.4以后版本号中,Throwable类支持异常链机制。Throwable 包括了其线程创建时线程运行堆栈的快照。它还包括了给出有关错误很多其它信息的消息字符串。最后,它还能够包括 cause(原因):还有一个导致此 throwable 抛出的 throwable。它也称为异常链 设施,由于 cause 自身也会有 cause,依此类推,就形成了异常链,每一个异常都是由还有一个异常引起的。
通俗的说,异常链就是把原始的异常包装为新的异常类,并在新的异常类中封装了原始异常类,这样做的目的在于找到异常的根本原因。
通俗的说,异常链就是把原始的异常包装为新的异常类,并在新的异常类中封装了原始异常类,这样做的目的在于找到异常的根本原因。
通过Throwable的两个构造方法能够创建自己定义的包括异常原因的异常类型:
Throwable(String message, Throwable cause)
构造一个带指定具体消息和 cause 的新 throwable。
Throwable(Throwable cause)
构造一个带指定 cause 和 (cause==null ? null :cause.toString())(它通常包括类和 cause 的具体消息)的具体消息的新 throwable。
getCause()
返回此 throwable 的 cause;假设 cause 不存在或未知,则返回 null。
initCause(Throwable cause)
将此 throwable 的 cause 初始化为指定值。
在Throwable的子类Exception中,也有类似的指定异常原因的构造方法:
Exception(String message, Throwable cause)
构造带指定具体消息和原因的新异常。
Exception(Throwable cause)
依据指定的原因和 (cause==null ? null : cause.toString()) 的具体消息构造新异常(它通常包括 cause 的类和具体消息)。
因此,能够通过扩展Exception类来构造带有异常原因的新的异常类。
Exception(String message, Throwable cause)
构造带指定具体消息和原因的新异常。
Exception(Throwable cause)
依据指定的原因和 (cause==null ? null : cause.toString()) 的具体消息构造新异常(它通常包括 cause 的类和具体消息)。
因此,能够通过扩展Exception类来构造带有异常原因的新的异常类。
七、Java异常处理的原则和技巧
1、避免过大的try块,不要把不会出现异常的代码放到try块里面,尽量保持一个try块相应一个或多个异常。
2、细化异常的类型,不要无论什么类型的异常都写成Excetpion。
3、catch块尽量保持一个块捕获一类异常,不要忽略捕获的异常,捕获到后要么处理,要么转译,要么又一次抛出新类型的异常。
4、不要把自己能处理的异常抛给别人。
5、不要用try...catch參与控制程序流程,异常控制的根本目的是处理程序的非正常情况。
2、细化异常的类型,不要无论什么类型的异常都写成Excetpion。
3、catch块尽量保持一个块捕获一类异常,不要忽略捕获的异常,捕获到后要么处理,要么转译,要么又一次抛出新类型的异常。
4、不要把自己能处理的异常抛给别人。
5、不要用try...catch參与控制程序流程,异常控制的根本目的是处理程序的非正常情况。
參考资料
主要是Java API文档(1.5版)、和我以前看过的一些书籍,也有一些其它零散资料。主要
主要是Java API文档(1.5版)、和我以前看过的一些书籍,也有一些其它零散资料。主要
电子书籍有:
Java2參考大全
Thinking in Java
Java核心技术(卷1)
原文出自:http://lavasoft.blog.51cto.com/62575/18920/
Java2參考大全
Thinking in Java
Java核心技术(卷1)
原文出自:http://lavasoft.blog.51cto.com/62575/18920/
java异常处理
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。