异常Throwable
1.有效处理java异常三原则
java中异常提供了一种识别及响应错误情况的一致性机制,有效地异常处理能使程序更加健壮,易于调试。异常之所以是一种强大的调试手段,在于其回答了以下三个问题:
- 什么出了错?
- 在哪里出错?
- 为什么出错?
有三个原则可以帮助你在调试过程中最大限度的使用好异常:
- 具体明确
- 提早抛出
- 延迟捕获
通过杜撰个人财务管理器类JCheckbook进行讨论,JCheckbook用于记录及追踪诸存取款,票据开具之类的银行账户活动。
1.1具体明确
java定义了一个异常类的层次结构,以Throwable开始,扩展出Error和Exception,而Exception又扩展出RuntimeException。
图一,java异常层次结构
这四个类是泛化的,并不提供出错信息,虽然实例化这几个类语法上合法(如:new Throwable()),java提供了大量异常子类,如果贴近业务,你也可以定义自己的异常类。
1.1.1捕获异常时尽量明确很重要。java让明确捕获异常变得容易,因为我们可以对同一try块定义多个catch块,从而对每一种异常分别进行恰当处理。
File prefsFile = new File(prefsFilename); try{
readPreferences(prefsFile);
}
catch (FileNotFoundException e){
// alert the user that the specified file
// does not exist
}
catch (EOFException e){
// alert the user that the end of the file
// was reached
}
catch (ObjectStreamException e){
// alert the user that the file is corrupted
}
catch (IOException e){
// alert the user that some other I/O
// error occurred
}
最后,我们注意到JCheckbook并没有在readPreferences()中捕获异常,而是将捕获和处理异常留到用户界面层来做(Controller层),这样就能用对话框或其他方式来通知用户。这被称为“延迟捕获”。
1.2提早抛出
异常堆栈信息提供了导致异常出现的方法调用链的精确顺序,包括每个方法名调用的类名,方法名,代码文件名甚至行数,以此来精确定位异常出现的现场。
java.lang.NullPointerException
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:103)
at jcheckbook.JCheckbook.readPreferences(JCheckbook.java:225)
at jcheckbook.JCheckbook.startup(JCheckbook.java:116)
at jcheckbook.JCheckbook.<init>(JCheckbook.java:27)
at jcheckbook.JCheckbook.main(JCheckbook.java:318)
通过逐步回退跟踪堆栈信息并检查代码,我们可以确定错误原因是向readPreferences()传入了一个空文件名参数。
public void readPreferences(String filename)
throws IllegalArgumentException{
if (filename == null){
throw new IllegalArgumentException("filename is null");
} //if
//...perform other operations...
InputStream in = new FileInputStream(filename);
//...read the preferences file...
}
通过提早抛出异常(又称"迅速失败"),异常得以清晰又准确。堆栈信息立即反映出什么出了错(提供了非法参数值),为什么出错(文件名不能为空值),以及哪里出的错(readPreferences()的前部分)。
这样我们的堆栈信息就能如实提供:
java.lang.IllegalArgumentException: filename is null
at jcheckbook.JCheckbook.readPreferences(JCheckbook.java:207)
at jcheckbook.JCheckbook.startup(JCheckbook.java:116)
at jcheckbook.JCheckbook.<init>(JCheckbook.java:27)
at jcheckbook.JCheckbook.main(JCheckbook.java:318)
通过在检测到错误时立刻抛出异常来实现迅速失败,可以有效避免不必要的对象构造或资源占用,比如文件或网络连接。同样,打开这些资源所带来的清理操作也可以省却。
1.3延迟捕获
捕获之后该拿异常怎么办?最不应该的就是什么都不做。适当分离用户界面代码和程序逻辑就可以提高我们代码的可重用性。
在有条件处理异常之前过早捕获它,通常会导致更严重的错误和其他异常。
例如:readPreferences()方法在调用FileInputStream构造方法时立即捕获和记录可能抛出的FileNotFoundException
public void readPreferences(String filename){
//...
InputStream in = null;
// DO NOT DO THIS!!!
try{
in = new FileInputStream(filename);
}
catch (FileNotFoundException e){
logger.log(e);
}
in.read(...);
//...
}
分析:上面的代码在完全没有能力从FileNotFoundException中恢复过来的情况下就捕获了它。如果文件无法找到,下面的方法显然无法读取它。
调试程序时,本能告诉我们要看日志最后面的信息。那将会是NullPointerException,非常让人讨厌的是这个异常非常不具体。错误信息不仅误导我们什么出了错(真正的错误是FileNotFoundException而不是NullPointerException),还误导了错误的出处。真正 的问题出在抛出NullPointerException处的数行之外,这之间有可能存在好几次方法的调用和类的销毁。
结论【抛异常】:既然readPreferences() 真正应该做的事情不是马上捕获这些异常,把责任交给 readPreferences()的调用者,让它来研究处理配置文件缺失的恰当方法,它有可能会提示用户指定其他文件,或者使用默认值,实在不行的话也 许警告用户并退出程序。把异常处理的责任往调用链的上游传递的办法,就是在方法的throws子句声明异常。
当然,你的程序最终需要捕获异常,否则会意外终止。但这里的技巧是在合适的层面捕获异常,以便你的程序要么可以从异常中有意义的恢复并继续下去,而不是导致更深入的错误;
- 如果你不能处理异常,不要捕获该异常。
- 如果要捕获,应该在异常源近的地方捕获它。
- 不要捕获异常后,什么也不做。
- 除非你要重新抛出异常,否则把它log起来。
- 当一个异常被重新包装,然后重新抛出的时候,不要打印statck trace(System.out.println是高代价的,会降低系统吞吐量,在生产环境中别用异常的printStackTrace()方法,会默认打到控制台上)
- 用自定义的异常类,不要每次都抛出java.lang.Exception。方法的调用者可以通过Throw知道有哪些异常需要处理,所以它是自我描述。
- 如果编写业务逻辑,对于终端无法修复的错误,系统应该抛出非检查异常(unchecked exception);如果编写一个第三方的包给其他的开发人员,对于不可修复的错误,要用需检查的异常(checked exception)。
2.异常基础
java语言采取了统一异常处理的机制。
Exception是所有异常的父类,任何异常都扩展Exception类。Exception相当于一个错误类型,采用异常的好处就是可以精确定位程序出错的源码位置,获取详细的错误信息。
Java异常处理通过五个关键字来实现,try,catch,throw ,throws, finally。具体的异常处理结构由try….catch….finally块来实现。try块存放可能出现异常的java语句,catch用来捕获发生的异常,并对异常进行处理。Finally块用来清除程序中未释放的资源。不管理try块的代码如何返回,finally块都总是被执行。
2.1Checked异常还是unChecked异常?
SQLException是checked异常。当调用createStatement方法时,java强制调用者必须对SQLException进行捕获处理。
public String getPassword(String userId){
try{
……
Statement s = con.createStatement();
……
Catch(SQLException sqlEx){
……
}
……
}
或者
public String getPassword(String userId)throws SQLException{
Statement s = con.createStatement();
}
(当然,像Connection,Satement这些资源是需要及时关闭的,这里仅是为了说明checked 异常必须强制调用者进行捕获或继续抛出)
unChecked异常也称为运行时异常,通常RuntimeException都表示“用户”无法恢复的异常,如无法获得数据库连接,不能打开文件等。虽然用户也可以像处理Checked异常一样捕获unChecked异常。但是如果调用者并没有去捕获unChecked异常时,编译器并不会强制你那么做。
举个栗子:
// 将字符串类型转换为整型数值
String str = “123”;
int value = Integer.parseInt(str);
Integer.parseInt()源码:
public static int parseInt(String s) throws NumberFormatException
当传入的参数不能转换成相应的整数时,将会抛出NumberFormatException。因为NumberFormatException扩展于RuntimeException,是unChecked异常。所以调用parseInt方法时无需要try…catch。
java推荐人们在应用代码中应该使用checked异常。但是这样会带来很多问题,导致了太多的try...catch代码,同时也导致了很多难以理解的代码产生。
当开发人员必须捕获一个自己无法正确处理的checked异常,通常是重新封装成一个新的异常后抛出,这没有给程序带来好处,反而代码难以理解。
checked异常导致破坏接口方法:
一个接口上的一个方法已被多个类使用,当为这个方法额外添加一个checked异常时,那么所有调用此方法的代码都需要修改。
2.2对于checked与unChecked异常的使用原则:
2.3自定义异常
一般情况下尽量不要去设计新的异常类,而是尽量使用java中已经存在的异常类。
不管是新的异常是chekced异常还是unChecked异常。我们都必须考虑异常的嵌套问题。我们在定义一个新的异常类时,必须提供这样一个可以包含嵌套异常的构造函数。并有一个私有成员来保存这个“起因异常”。
所以我们需要覆写printStackTrace方法来显示全部的异常栈跟踪。包括嵌套异常的栈跟踪。
Checked异常类继承Exception,unChecked异常类继承RuntimeException。
2.4如何记录异常
作为一个大型应用系统都需要用日志文件来记录系统运行,以便于跟踪和记录系统的运行情况。系统发生的异常理所当然的需要记录在日志系统中。
异常应该在最初产生的位置记录!!
如果捕获到一个异常,但是这个异常可以处理,则无需记录异常(unCheckedException)
捕获到一个未记录过的异常或外部系统异常时,应该记录异常的详细信息
在javaEE项目中异常处理从逻辑上分为多层,表现层、业务层、数据库访问层。
一般地,我们需要定义一个unChecked异常,让集成层接口的所有方法都声明抛出这unChecked异常。实现类进行捕获。
public DataAccessException extends RuntimeException{
……
}
public interface UserDao{
public String getPassword(String userId)throws DataAccessException;
} public class UserDaoImpl implements UserDAO{
public String getPassword(String userId)throws DataAccessException{
String sql = “select password from userInfo where userId= ‘”+userId+”’”;
try{
…
//JDBC调用
s.executeQuery(sql);
…
}catch(SQLException ex){
throw new DataAccessException(“数据库查询失败”+sql,ex);
}
}
}
对于表示层,一般情况下不需要捕获异常,即使捕获异常也不要将原信息展现给用户,要友好展示。
可以对表示层进行捕获,利用springmvc进行统一异常处理,简化代码,减少复用性,调高代码质量。
参考文章链接:
http://klyuan.iteye.com/blog/72170
http://blog.csdn.net/luqin1988/article/details/7970792
http://www.onjava.com/pub/a/onjava/2003/11/19/exceptions.html 对应的译文,不怎么准确:http://blog.sciencenet.cn/blog-252888-761119.html
http://www.oschina.net/question/92866_15634
http://www.importnew.com/1701.html
http://sunflowers.iteye.com/blog/767175
异常Throwable的更多相关文章
- 异常Throwable类
所有异常类型都是Throwable类的子类,它派生出两个子类 Error和Exception Error类:表示紧靠程序本身无法恢复的严重错误,如内存溢出,动态链接失败,虚拟机错误 ...
- 详解Java异常Throwable、Error、Exception、RuntimeException的区别
在Java中,根据错误性质将运行错误分为两类:错误和异常. 在Java程序的执行过程中,如果出现了异常事件,就会生成一个异常对象.生成的异常对象将传递Java运行时系统,这一异常的产生和提交过程称为抛 ...
- 异常-Throwable的几个常见方法
package cn.itcast_04; import java.text.ParseException; import java.text.SimpleDateFormat; import jav ...
- JavaEE基础(十九)/异常和File
1.异常(异常的概述和分类) A:异常的概述 异常就是Java程序在运行过程中出现的错误. B:异常的分类 通过API查看Throwable Error 服务器宕机,数据库崩溃等 Exception ...
- JavaSE笔记-异常
Java 异常 Throwable类的体系结构(一些常用的) 异常分类 checked,unchecked 区分:RuntimeException及其子类,Error类及其子类,是unchecked ...
- InvocationTargetException异常解析
InvocationTargetException异常由Method.invoke(obj, args...)方法抛出.) { throw new ZeroException("参数不能小于 ...
- Java_异常以及处理
目录 JAVA异常 异常的处理机制 自定义异常 写了一天的bug,来try...catch...finally了解一下.异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的. ...
- 【Java基础】【19异常&IO(File类)】
19.01_异常(异常的概述和分类) A:异常的概述 异常就是Java程序在运行过程中出现的错误. B:异常的分类 通过API查看Throwable Error 服务器宕机,数据库崩溃等 Except ...
- Java学习笔记26(异常)
异常的定义: Java代码在运行过程中发生的问题就是异常 异常类:出现问题就会常见异常类对象,并抛出异常的相关信息,异常的位置,原因 异常体系: Throwable类是java中所有错误或异常的父类 ...
随机推荐
- Rx操作符
[Rx操作符] 1.Observable.from()方法,它接收一个集合作为输入,然后每次输出一个元素给subscriber: Observable.from("url1", & ...
- datetime空值设置
Cause: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Incorrect datetime value: '' for column ...
- CRTD模拟MFG工单进行绑定优化
需求:按单按库生产的CRTD状态半成品工单重复创建问题 绑定成功案例: SELECT DEMANDLINEID,SUPPLYORDERID,DEMANDORDERID,QTYALLOCATED,ITE ...
- ORA-01555 snapshot too old
假设有一张6000万行数据的testdb表,预计testdb全表扫描1次需要2个小时,参考过程如下: 1.在1点钟,用户A发出了select * from testdb;此时不管将来testdb怎么变 ...
- python中matplotlib所绘制的图包含了很多的对象
上图中的top=‘off’意思是说顶部的grid lines 看不见. 去除frame,意思就是将这个矩形给去除掉,spine意思是脊柱 bars = plt.bar(pos, popularity, ...
- HDU-1176.免费馅饼(数字三角形变形)
看到网上大多都是逆向的总结,我来搞个正向的吧... 这道题想着是和数字三角形差不多的,但是最后愣是没有写出来,感受到一股菜意......哭唧唧.jpg 本题大意: 给定n个序列,每个序列包含两个数表示 ...
- 98. Validate Binary Search Tree (Tree; DFS)
Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as ...
- c# tcp协议发送数据
private void tcp_send(string data)//tcp协议转发数据 { TcpClient tcpClient = new TcpClient(); tcpClient.Con ...
- OSPF网络类型不一致路由无法计算的问题
晚上割接,远端的ASR9001-s网络类型为广播类型,本端为6509-e,网络接口类型修改成p2p后,OSPF邻居关系建立,但是路由无法计算.
- vue 父子组件相互传参
转自https://blog.csdn.net/u011175079/article/details/79161029 子组件: <template> <div> <di ...