java异常
几个需要注意到点:
1、finally语句:为异常处理提供了一个统一的出口,无论程序是否发生异常,都会执行,所以通常用来进行资源清理的工作,如关闭文件,清理数据库连连接,删除临时文件等;
2、重写方法抛出异常与原方法所抛出异常类型一致,或者不抛出异常,不能抛多抛少,抛的范围大或小。
3、子类方法不能比父类方法抛出更多的异常。
4、一个try块可以对应多个catch块,在catch异常时,要先捕获小的,再捕获大的;否则小的异常会被前面
catch块
捕获。
自定义异常
通过继承java.lang.Exception类来自定义异常。
怎么处理异常?
1、捕获并抛出运行时异常。不能一味的向上抛,如果抛到了用户界面层(或者说main函数),还不处理,那就直接显示给了用户,就不能给用户提供友好界面。异常在向上抛的过程中,也会给调用者带来麻烦,所以还是得处理。可以将异常try/catch,抛出运行时异常,调用者可以处理,也可以不处理。
try{.....
}catch (Exception e) {
throw new RuntimeException(e);
}
2、编译时异常用作返回值,通知调用者,发生错误。
下面是学习jaxp的dom解析方式来解析xml文档时,删除学生时,考虑到学生不存在的情况下,如何处理。
若不存在该学生,要通知给调用者,用来通知用户,当然可以通过改变返回值类型来实现,如删除成功则返回true,删除不存在该学生,则返回false。但在不改变返回值类型的情况下,可以
通过抛异常来通知调用者,将异常当做一种返回值来处理,同时为了保证能够传递方式某种
错误的信息,需要自定义异常,如StudentNotFoundException,若调用者遇
到该异常,就可以识别发生了什么错误,并可以给用户友好提示。先看代码:
删除学生:
//StudentDao.java
public void delete(String name) throws StudentNotFoundException{
//获得name标签列表,遍历,若相等,则获取该name标签的父节点的父节点,删除student标签
try {
Document document = XmlUtils.getDocument();//会抛出异常,所以下面找catch
NodeList list = document.getElementsByTagName("name");
for (int i = 0; i < list.getLength(); i++) {
if (list.item(i).equals(name)) {//找到匹配该名字的学生并删除
list.item(0).getParentNode().getParentNode().removeChild(list.item(i).getParentNode());
return;
}
throw new StudentNotFoundException();
}
}catch(StudentNotFoundException e){
throw e;
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
调用者:
//main.java...............System.out.print("请输入学生姓名:");
String name = br.readLine();
StudentDao dao = new StudentDao();
try {
dao.delete(name);
} catch (StudentNotFoundException e) {
System.out.println("删除的学生不存在!!!");
e.printStackTrace();
}
..............
可以看到程序抛了StudentNotFoundException异常,又catch,又抛出,到底在搞什么?
因为Document document = XmlUtils.getDocument(); 会抛出异常,所以需要下面catch (Exception e)来处理异常;
我们需要在学生不存在的时候抛出异常来通知调用者,所以抛出了异常(throw new StudentNotFoundException(); ) ;
但此时抛出的异常,又被catch (Exception e)处理掉了,那怎么使StudentNotFoundException异常让调用者catch到呢?
catch异常的时候,要先catch小的,在catch大的异常,所谓的小指的是子异常类,大则指父异常类。所以就在catch (Exception e)前面加了catch(StudentNotFoundException e)并把异常抛出去,由于此时该方法在catch中抛出了异常并没有相应的try/catch来处理该异常,则需要声明该方法抛出异常StudentNotFoundException。这样是不是调用者就可以在调用该方法时,发现StudentNotFoundException异常,并可以处理,通知用户。
3、实际项目中,可能发生多种多样的异常,通常定义一个包来封装这些自定义的异常类。
4、捕获抛出自定义运行时异常。
若即想通知调用者发生什么错误,又想给调用者选择权,既可以处理异常又可以不处理异常,则捕获异常,抛出自定义运行时异常(继承
RuntimeException类),抛出
运行时异常
异常的方法也可以不用进行异常声明。
下面结合学习jdbc时遇到的问题,
结合Service层来讲
DAO层异常处理。
UserDaoJdbcImpl.java中的addUser方法:
public void addUser(User user) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
String sql = "insert into user(name,birthday, money) values (?,?,?) ";
ps = conn.prepareStatement(sql);
ps.setString(1, user.getName());
ps.setDate(2, new java.sql.Date(user.getBirthday().getTime()));
ps.setFloat(3, user.getMoney());
ps.executeUpdate();//会出现异常
} catch (SQLException e) {
throw new DaoException(e.getMessage(), e);
} finally {
JdbcUtils.free(rs, ps, conn);
}
}
在执行
ps
.
executeUpdate
()方法时会出现异常,要怎么解决呢?
1、跑出异常,但定义的userDao接口中定义addUser方法是没有异常抛出的,java的异常机制可知,子类中的方法只能抛出比父类方法更少的异常,不能更多,所以如果抛出异常,则需要改动接口中的adduser方法,增加抛出异常的声明,但这样就破坏了接口,如果使用herbinate来实现数据userDao接口,而
Hibernate来访问数据库时不抛出异常,那么这个接口就不能使用,所以这种方法
不可行。
2、捕获并处理,良好的程序设计,不能仅仅捕获异常,打印堆栈信息;而是需要给调用者一个良好的提示。比较好的做法是,自定义一个异常类,表示异常类型,抛出给调用者,调用者就知道发生了什么异常。这里是定义了
运行时异常类
DaoException
,捕获
SQLException并抛出
运行时异常类
DaoException,这样调用者在调用方法时,若发生了异常,调用者就知道是在dao实现层发生了异常。这样做的好处是,不污染接口;通知调用者,发生了什么错误;同时调用者对异常具有选择性,既可以处理也可以选择不处理,比较灵活。
自定义异常类:
package dao;
public class DaoException extends RuntimeException {
private static final long serialVersionUID = 1L;
public DaoException() {
// TODO Auto-generated constructor stub
}
public DaoException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public DaoException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
public DaoException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
}