这个问题已经在iteye被讨论过很多了。robbin也发表过看法。现在我觉的有必要总结下。
围绕着这个问题的争论,主要集中在两点;一是效率,一是规范。还有少部分观点认为用异常作程序流程控制有时候会很方便。
以下面的代码为例:
public static boolean isDigit(String src){
try{
Integer.parseInt(src);
return true;
}catch(Exception e){
return false;
}
}
public static boolean isDigit(String src){
return src.matches("^\\d+$")
}
private static Pattern digitRegex=Pattern.complie("^\\d+$");
public static boolean isDigit(String src){
return digitRegex.matcher(src).matches();
}
第一个写法是从别人的帖子里抄过来的,原帖我找不到了。当时作者认为这样写好,因为方便,只有6行代码。
个人觉的这纯粹是一种蛋疼的写法。从效率上说它比第二种写法快,但是恐怕不怎么方便的吧,感觉绕了个大弯。
实际上应该推荐第三种写法,当然占用的内存稍微多一些,但它效率最高。第二种方法写法最简单。
Robbin举了另外的例子
try{
userService.add(user);
}catch(UserExistException e){
//在此处同名添加用户已存在的处理逻辑
}
个人认为如果为用户名字段添加了惟一性约束,这么写很好。如果没有惟一性约束恐怕就要这么做了
if(userDao.exist(user)){
throw new UserExistException(user);
}else{
userDao.save(user);
}
在没有惟一性约束的情况下,为什么不这么做?
if(!userDao.exist(user)){
return userDao.save(user);
}else{
return USER_EXISTED;
}
public static final int USER_EXISTED=-1;
不要说为了遵守第三范式什么的,数据量太大的时候,使用字符串做主键和增加太多约束,效率肯定降低。我参与过的所有项目,除了long型主键其它字段一律都不添加任何约束。
当然上面那个例子的返回值还可以改成枚举,个人更推荐使用枚举。不过这里只是个例子,本人太懒不想写太多代码。
究竟是不是要使用异常作为流程控制条件,恐怕还得依具体情况判断。
最后想说的是,不要为了面向对象而面向对象。
定义了太多的业务异常,然后依不同的业务情况去抛出它们,然后在方法的调用处捕获它们。个人一直觉的这是一种蛋疼的做法。
public LoginResult login(String username, String password){
User user=userDao.find(username);
if(user==null){
return LoginResult.USER_NAME_NOT_FOUND;
}else if(!user.getPassword.equals(password)){
return LoginResult.INCORRECT_PASSWORD;
}else{
return LoginResult.LOGIN_SUCCESS;
}
}
如果采用异常恐怕得这么做
public Userlogin(String username, String password){
User user=userDao.find(username);
if(user==null){
throw new UserNotFoundException(username);
}else if(!user.getPassword.equals(password)){
throw new IncorrectPasswordException(user,password);
}else{
return User;
}
}
为什么不定义一系列枚举,依照不同的业务处理结果返回不同的枚举值?
单看上面的两段代码恐怕没法判断哪个更简单。但是逻辑显然是差不多的。
整个登录流程肯定不会就这么完了,上面只是service层的代码。在action层肯定还要根据service的执行状况做后续处理。
单纯从登录这个操作来看,个人更倾向于第一种做法,到了action层,只需要简单的向浏览器响应枚举值对应的字符串作为结果即可,代码大大减少,而且效率绝对比异常控制要高。
在浏览器端可以根据返回的字符串做后续处理。如果登录流程没有js参与,action也可简单的根据返回的枚举值做后续处理。
至少直到目前为止我还没在开发过程中发现非用异常做流程控制不可的理由。
当然hibernate里面用了大量异常作流程控制。如果它不这样做,恐怕就要增加不少数据库访问量,这样在异常方面造成的效率影响没有了,却增加了网络通讯和数据库访问量,显然是得不偿失的。因此,减少数据库访问量、网络数据流量和网络访问次数恐怕是使用异常做程序控制的最大理由。