异常分为运行时的异常和检测异常:
java提供了两种异常机制。一种是运行时异常(RuntimeExepction),一种是检查式异常(checked execption)。
运行时的异常就是在java虚拟机正常运行的时候抛出的异常:
常见的五类运行时的异常:
IllegalArgumentException,
NullPointerException
ArrayStoreException 试图将错误类型的对象存储到一个对象数组时抛出的异常
ClassCastException 试图将对象强制转换为不是实例的子类时,抛出该异常
IllegalArgumentException 抛出的异常表明向方法传递了一个不合法或不正确的参数
IndexOutOfBoundsException 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出
NoSuchElementException 表明枚举中没有更多的元素
NullPointerException 当应用程序试图在需要对象的地方使用 null 时,抛出该异常
等
运行时的异常主要是由于程序员的逻辑错误引起的,这个时候就会导致程序的异常退出,例如android界面的空指针异常。
1、对应运行时的异常,我们可以使用 try catch进行处理,也可以不处理,要么是线程中止,要么是主程序终止。
我们来看两个常用的运行时的异常:
列如自己定义可一个模块,提供给别人调用的时候,我们一定要进行输入参数的判断:
public static void copyDirectoryToDirectory(File srcDir, File destDir) throws IOException {
if (srcDir == null) {
throw new NullPointerException("Source must not be null");
}
if (srcDir.exists() && srcDir.isDirectory() == false) {
throw new IllegalArgumentException("Source '" + destDir + "' is not a directory");
}
//...
}
这个时候我们就可以抛出一个运行时的异常NullPointerException直接终止程序。
运行时异常的常用案例二:
public static GateWayCaller getGateWayCaller(String serviceKey)
{
if("alerting".equals(serviceKey))
{
return new AlertingCaller();
}
else if("report".equals(serviceKey))
{
return new ReportCaller();
}
//...
else
{
return null;
}
}
当调用者调用的时候,它不知道你会返回一个null对象,如果调用者没有对返回的值进行判断null的处理,就要引起空指针异常,所以写代码的时候,我们尽量不要使用返回null的处理,这里我们可以创建一个运行时的异常,直接退出程序
if("alerting".equals(serviceKey))
return new AlertingCaller();
else if("report".equals(serviceKey))
return new ReportCaller();
//...
else
throw new RuntimeException("Invalid Service Key!");
运行时的异常案例3:在java web开发中数据库dao层不对异常进行任何处理,将异常抛出,在业务层中对异常进行处理,如果不要继续把异常throws给调用者,就直接抛出一个运行时的异常
package com.weiyuan.goods.user.dao;
import java.sql.SQLException;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import cn.itcast.jdbc.TxQueryRunner;
public class UserDao {
//操作数据库
private TxQueryRunner qr = new TxQueryRunner();
/***
* 查询用户名是否存在
* @throws SQLException
*/
public boolean ajaxValidateLoginName(String loginName) throws SQLException{
//获得满足记录的数目是对象,返回一个整数,整数是单行单列使用ScalarHandler
String sql ="select count(*) from t_user where loginname=?";
Number num = (Number) qr.query(sql, new ScalarHandler(),loginName);
int count = num.intValue();
if(count>0){
return true;
}
return false;
}
/***
* 查询邮箱是否存在
* @throws SQLException
*/
public boolean ajaxValidateEmain(String email) throws SQLException{
//获得满足记录的数目是对象,返回一个整数,整数是单行单列使用ScalarHandler
String sql ="select count(*) from t_user where email=?";
Number num = (Number) qr.query(sql, new ScalarHandler(),email);
int count = num.intValue();
if(count>0){
return true;
}
return false;
}
}
在业务层对异常进行处理,业务层不要通知调用者存在业务,在对异常进行处理的时候抛出一个运行时的异常
package com.weiyuan.goods.user.service;
import java.sql.SQLException;
import javax.management.RuntimeErrorException;
import com.weiyuan.goods.user.dao.UserDao;
public class UserService {
private UserDao dao = new UserDao();
public boolean ajaxValidateLoginName(String loginName) {
try {
return dao.ajaxValidateLoginName(loginName);
} catch (SQLException e) {
// TODO Auto-generated catch block
throw new RuntimeException(e.getMessage());
}
}
public boolean ajaxValidateEmail(String email) {
try {
return dao.ajaxValidateLoginName(email);
} catch (SQLException e) {
// TODO Auto-generated catch block
throw new RuntimeException(e.getMessage());
}
}
}
检测异常也叫做非运行时候的异常,常见的非运行的异常有下面的几种形式,类型上都属于Exception类及其子类
IOException
SQLExCeption
用户自定义的异常
使用try…catch…finally语句块进行捕获
在产生异常的方法所在的方法声明throws Exception
1.throws是表明方法抛出异常,需要调用者来处理,如果不想处理就一直向外抛,最后会有jvm来处理;
2.try catch 是自己来捕获别人抛出的异常,然后在catch里面去处理;
对应检测异常,操作系统要求我们必须对其处理,要不使用try catch 处理 要不使用throws进行声明由调用者进行处理
我们来看一个检测的异常的例子
第一种对异常进行声明:
public boolean ajaxValidateEmail(String email) throws SQLException{
//获得满足记录的数目是对象,返回一个整数,整数是单行单列使用ScalarHandler
String sql ="select count(*) from t_user where email=?";
Number num = (Number) qr.query(sql, new ScalarHandler(),email);
int count = num.intValue();
if(count>0){
return true;
}
return false;
}
第二种对异常进行逻辑处理
/***
* 查询邮箱是否存在
* @throws SQLException
*/
public boolean ajaxValidateEmail(String email){
//获得满足记录的数目是对象,返回一个整数,整数是单行单列使用ScalarHandler
String sql ="select count(*) from t_user where email=?";
Number num;
try {
num = (Number) qr.query(sql, new ScalarHandler(),email);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int count = num.intValue();
if(count>0){
return true;
}
return false;
}
第三种自定义异常:
自定义异常通常是定义一个继承自Exception类的子类。一般情况下我们都会直接继承自Exception类,而不会继承某个运行时的异常类。
5.1、创建自定义异常:
public class MyException extends Exception{
public MyException(){
super();
}
public MyException(String msg){
super(msg);
}
}
对应非运行的异常,都代表了一个异常的场景,作为程序员不能直接使用一个Exception进行进行处理,而应该对每一个异常场景进行处理,例如:
try {
} catch (SQLException e) {
}catch(FileNotFoundException){
}
不要直接:
try {
} catch (Exception e) {
也不能直接将所有的异常都统一使用一个Exception跑出去
public boolean ajaxValidateEmail(String email) throws FileNotFoundException, SQLException{
不能写成
public boolean ajaxValidateEmail(String email) throws Exception{
4 对应函数的返回值和异常的区别
含义的返回值是一个业务操作成功返回的结果,不能把返回值作为一个业务是否执行成功的标志,例如 如果返回值是true就表示业务执行成功,这是错误的,如果返回值是true表示的是该业务的返回值就是true,
通过异常我们可以知道这个业务失败的原因
User login(String username, String password); throws UserNotFoundException, PasswordNotMatchException; 这个模块的功能定义,不能通过函数的返回值来确定函数释放成功,返回值是表示函数内部逻辑处理的返回结果,通过异常来表示函数的操作是否失败,失败的原因是啥。
案例3:对应throws new Exception 和 throws new RuntimeException 的区别
1、在业务操作的时候,如果业务操作失败,我们应该抛出throws new Exception提示用户业务操作失败的原因。抛出throws new Exception 就是业务层需要将业务失败的异常通知调用者,让调用者对异常进行处理
2、但是在业务操作的过程中,如果是系统异常,列如sql数据库的异常,它不是业务失败的异常,这个时候业务层不应该将异常通过通知调用者,但是它又是异常,这个时候直接 throw new RuntimeException 直接退出程序,禁止业务的操作。
我们来看用用户注册的时候,会发送邮件到用户的邮箱,当用户点击邮件的激活的时候,会将激活码携带到后台,后台收到验证码之后会和保存到数据库中该用户的初装的激活码进行对比,如果相同设置用户的集合状态为true
激活的业务操作的结果就是下面的三种:
1、激活成功
2、激活码无效
3、用户以前就已经激活过,不能重复注册
我们来看程序的代码:
dao层、通过激活码查找用户,将用户的激活状态设置成true
/*
* 通过激活码获得用户
* */
public User findUserByActivationCode(String activationCode) throws SQLException{
String sql = "select * from t_user where activationCode = ?";
return qr.query(sql, new BeanHandler<User>(User.class),activationCode);
}
/*
* 设置用户的激活状态
* */
public void setUserActivationCode(String uuid,int status) throws SQLException{
String sql = "update t_user set status = ? where uid = ? ";
qr.update(sql,status,uuid);
}
业务层的操作
/*设置用户的激活状态*/
public void activation(String activationCode) throws Exception{
//1 、通过激活码查找对应的用户信息
try {
User user = dao.findUserByActivationCode(activationCode);
if(user == null){
throw new Exception("无效的激活码");//业务异常,业务失败
}
if(user.getStatus()== 1){
throw new Exception("用户已经既激活,不要二次激活");//业务异常,业务失败
}
dao.setUserActivationCode(user.getUid(), 1); //1表示激活
} catch (SQLException e) {
// TODO Auto-generated catch block
throw new RuntimeException(e.getMessage()); // 不是业务的异常吗,而是电脑环境系统数据库的异常,直接退出线程,无法进行业务的操作了
}
}
控制层:
/*
* 当用户从邮箱点击的激活的时候会调用该方法,并且把激活码传递过来
*
* */
public String activation(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String activationCode = request.getParameter("activationCode");
System.out.println("email activationCode is :"+activationCode);
try {
service.activation(activationCode);
//激活成功
request.setAttribute("code", "success"); //msg.jsp已经code的值来显示错误信息还是正确的信息
request.setAttribute("msg", "激活成功");
return "f:/jsps/msg.jsp";
} catch (Exception e) {
//将业务操作的异常信息在msg.jsp中显示出来
String msg = e.getMessage();
request.setAttribute("code", "error"); //msg.jsp已经code的值来显示错误信息还是正确的信息
request.setAttribute("msg", msg);
return "f:/jsps/msg.jsp";
}
}
通过代码:我们就可以知道,在业务层中,业务失败存在两种异常:
throw new Exception("无效的激活码");//业务异常,业务失败
throw new Exception("用户已经既激活,不要二次激活");//业务异常,业务失败
这两种异常是业务操作失败的异常,我们需要通知servlet进行处理,提示业务操作的结果,
但是对应dao层抛出的
SQLException 的异常,不是业务操作的结果,我们不需要让调用者知道该异常,但是我们必须对该异常处理,所以抛出
throw new RuntimeException(e.getMessage()); // 不是业务的异常吗,而是电脑环境系统数据库的异常,直接退出线程,无法进行业务的操作了
这就是
throw new RuntimeException 和 throw new Exception的区别,
throw new RuntimeException就是不需要让调用者知道的异常,但是内部需要需要对例如对sql异常进行处理,所以就抛出throw new RuntimeException