java异常处理机制

java异常类

java.lang.Throwable

方法:

getMessage(); 获得异常描述

printStackTrance(); 打印异常堆栈

 

关于Throwable

** StackTraceElement。一个final类,代表栈轨迹中的元素,一个异常可能有多个元素。

一.打印栈轨迹的方法

  1. 主动调用Throwable对象的printStackTrace()=printStackTrace(System.err),printStackTrace(PrintStream),printStackTrace(PrintWriter)中的其中一个。
  2. 如果一个Exception没有被处理,直接在main方法后面throws,程序退出前将调用异常的printStackTrace()方法,最终是Exception in thread "main" + printStackTrace()

栈轨迹

  1. 栈轨迹显示了"把你带到异常抛出的地点"。
  2. 上面三个方法调用this.getOurStackTrace()获得栈轨迹;同时Throwable提供了public的方法getStackTrace()获得栈轨迹(实际返回getOurStackTrace().clone())。
  3. getStackTrace()将返回栈轨迹中元素所构成的数组,其中每一个元素都是一帧。元素0是栈顶元素,栈顶元素为调用序列里的最后一个方法,栈底元素是第一个方法。

fillInStackTrace方法

  1. native fillInStackTrace()方法将返回一个Throwable对象,它是通过把当前调用栈信息填入原来那个异常对象儿建立的,所以返回的还是原来的异常。
  2. 调用此方法的那一行将成为异常新的发生地,有关原来异常发生点的信息会丢失。它的效果等价于捕获一个异常后,重新抛出另外一种异常。两者不同的 是,fillInStackTrace后的异常还是原来的异常(只是少了栈轨迹而已);而重新抛出一个异常的话,完全跟原异常信息无关了(当然也没有栈轨 迹)。

异常链

  1. 常常会再捕获一个异常后抛出另外一个异常,并且希望把异常原始信息保存下来,这被称为异常链。
  2. 在JDK1.4以前,程序员必须自己编写代码来保存原始异常信息,
  3. 现在所有Throwable的子类子构造器中都可以接受一个cause对象作为参数,这个cause就异常原由,代表着原始异常,即使在当前位置创建并抛出行的异常,也可以通过这个cause追踪到异常最初发生的位置。
  4. 只有Error,Exception,RunimeException提供了带cause参数的构造器,其他的所以异常就只有通过initCause()来设置cause了。

 

effective java 和think in java

think in java

  1. 发现错误的最佳时期是编译期间,然而编译期间并不能找出所有数据,余下的问题必须在运行期间解决。
  2. switch case语句里如果throw Exception的话是不需要break的。
  3. 异常处理理论上有两种基本模型。终止模型,java和c++支持的模型,将假设错误非常关键,一旦异常被抛出,就表明错误已经无法挽回,也不能继续执行;恢复模型,遇到错误不能抛出异常,而是调用方法来修正错误。
  4. 尽量不要捕获RuntimeException,但还是可以在代码中抛出RuntimeException类型的异常。
  5. 如果一个方法只申明了异常,但并没有在方法体抛出任何异常,调用此方法的方法是没有异常可以捕获的。
  6. 丢失异常:1.不使用异常链;2.从finally语句返回。
  7. 异常的限制:1.父类异常大于等于子类异常,子类要么不抛,要么抛出父类异常或父类异常的子异常。2.如果一个对象声明为父类引用时,调用此对象的方法, 抛出父类里声明的异常;如果一个对象声明为是自己引用时,调用此对象的方法,当然抛出自己声明的异常,跟父类无关。3.异常声明不是方法签名的一部分,方 法签名由方法名字和参数个数及类型组成,所以异常声明不能作为重载的判断标准。4.构造器可以抛出任何异常,而不必理会父类构造器抛了什么异常。
  8. 在创建需要清理的对象之后,立即进入try-finally块清理此对象
  9. 异常匹配顺序:找出最近的异常;子类的对象也可以匹配其父类的处理程序。找到匹配的后,不再继续查找。
  10. 异常的重要准则是只有在你知道如何处理的情况下才捕获异常。重要目标是把错误处理的代码同错误发生的地点相分离。举个列子service-dao两层,在 dao里产生了SQLException我无需处理直接抛出,到了service层,我知道要将其转换成自己的业务异常。

 

effective java

  1. 基于异常的模式:用try catch然后忽略异常的手段来达到你想要的目的。
  2. 异常应该只用于异常的情况下,它们永远不应该用于正常的控制流。对此我不赞同。、
  3. 对可恢复的情况使用受检异常,对编程错误使用运行时异常。何为可恢复的情况,是指不改变代码的基础上,这个异常情况是可以恢复的,比喻 IOExcepion可能是网络的问题,解决了网络,代码就能继续运行下去了;何为错误,当然指不能恢复的啦,比喻从你控制范围之外传递进来的null引 用,所以,此类异常都是程序员的问题,作为程序员,应该在代码中进行必要的检查。
  4. 异常类越少,意味着内存印迹就越小,装载这些类的时间开销也越少。
  5. 异常转译:高层的实现应该捕获低层的异常,同时抛出可以按照高层抽象进行解释的异常。异常链就是一种特殊的异常转译形式,高层异常可以通过getCause来获得低层的异常。
  6. 异常的细节信息应该包含所有的对该异常有贡献的参数和域的值。比喻IndexOutOfBoundsException应该包含 lowerBound,upperBound,Index三个参数。遗憾的是Java平台里并没有广泛的使用这种做法,而是全部清一色的简单继承了下父 Exception。
  7. 失败原子性:失败的方法调用应该使对象保持在调用前的状态。如果没有size==0的判断,可能导致size域同之前的不一致。

try catch finally break continue return

准则

finally一般情况总会执行,无论在try块里return break continue。除了调用System.exit(0)方法,该方法终止java虚拟机进程。

try块里return之前,finally会被执行

return语句会把后面的值复制到一份用来返回,如果return的是基本类型的,finally里对变量的改动将不起效果,如果return的是引用 类型的,改动将可以起效果。执行顺序:将要return时调用jsr指令----->finally代码块,finally代码块最后执行ret指 令----->继续return。

finally里的return语句会把try块里的return语句效果给覆盖掉。finally语句里的return,break,continues,抛出异常,finally子句结尾处的ret指令永远不会执行,不会在去调用finally的地方了。

我们需要做的是

  1. 最好把return放到方法尾而不要在try里return。
  2. 如果非要的话:不要在try块和finally块里都包含return;如果在try块里return, 则不要在finally块里操作被return的变量。

 

两个子类:

Error:仅靠程序本身无法恢复的严重错误,比如内存不足,java虚拟机的方法调用堆栈溢出。

大多数情况下,遇到这样的错误时,程序只有死的份。

StackOverError,OutOfMemoryError

Exception:表示程序可以处理的异常。程序出现异常的时候,应该尽可能地处理异常,并且

使得程序恢复运行,而不应该随意中止。

EOFException,FileNotFoundException

 

RuntimeException异常及其子类:运行时异常

java编译器不会检查它,这种异常没有try catch语句捕获,也没有throw字句抛出,还是编译通过。

unchecked Exception

运行时异常表示无法让程序恢复运行的异常,导致这种异常的原因通常是由于执行了错误操作。一旦出现错误操作,建议

终止程序,因此java编译器不检查这种异常。

运行时异常应该尽量避免,在程序调试阶段,遇到这种异常的时候,正确的做法是改进程序的设计和实现方式,修改程序

中的错误,从而避免这种错误。

如果捕获并且使程序恢复运行不是明智的行为:

1.这种异常一旦发生,损失严重。

2.即使程序恢复运行,也可能会导致程序的业务逻辑错乱,甚至导致更严重的异常,或者得到错误的运行结果。

 

受检异常,除了RuntimeException及其子类的所有Exception及其子类。

Checked Exception

这种异常要么用try..catch捕获,要么用throw子句声明抛出,否则编译不会通过。

可以处理和修复的异常,如果抛出异常的方法本身不能处理它,那么方法调用者应该去处理,如此递推,知道在某一层可以处理它,

就进行必要的处理,而不至于终止程序。

 

 

Error和java运行时异常:

相同:java编译器都不会检查他们,当程序出现错误的时候,都死。

不同:Error及其子类是由java虚拟机抛出,一般不可拓展。

RuntimeException表示程序代码中的错误,可以自定义。

 

 

异常转义和异常链

 

 

 

异常处理原则

1.异常只能用于非正常情况

2.为异常提供文档说明

3.尽可能地避免异常

**许多运行时异常是由于代码中的错误引起的,修改代码,改进实现方式

**提供状态测试方法,某种状态下,不适合这种操作,引起异常。

4.保持异常的原则性

**检查方法的参数是否有效,确保异常发生的时候还没有改变初始状态

**恢复代码

**在对象的临时对象上进行操作,当操作成功后,把拷贝的内容复制到原来的对象上

5.避免过于庞大的try代码块

**分段处理

6.在catch子句中指定具体的异常

try{

 //code

}catch(Exception e){//code}

**俗话说对症下药,对不同的异常通常有不同的处理方式。以上代码意味着对所有异常采用相同的方式,这往往是不现实的。

**会捕获本来应该抛出的运行时异常,掩盖程序中的错误。

7.不要在catch代码块中忽略被捕获的异常

**处理异常:针对异常采取一些行动,比如弥补造成的损失或者给出警告。

**重新抛出异常:如果当前时间或者环境下还不能处理该异常,就应该重新抛出。

**进行异常转译:把原始异常包装成适合当前抽象层的另一种异常,再将其抛出。

**假如在catch代码块中不能采取任何措施,那么就不要捕获异常,而是用throws子句声明抛出异常。

 

 

 

posted @ 2014-03-23 22:04  qiumiaod  阅读(223)  评论(0编辑  收藏  举报