最近才领悟到exception在开发中的好处,不知是否理解有误

时间:2021-02-20 19:12:01
例如,一个用户注册流程:
我们要根据用户的输入来返回给用户不同的结果;
“用户名格式错误”
“密码格式错误”
“邮箱格式不正确”

我不知道大家平时是怎么做的,我做这样的事情有两种处理方法:
1.有几个检测属性就写几个检测方法,然后在一个主控制类里做处理
if(Checker.invalidUserName)
  return Constant.INVALID_USER_NAME;
if(Checker.invalidEmail)
  return Constant.INVALID_EAMIL;
.......

2.或者简单些,直接写个方法,让它反回个int,0是密码错误,1是用户名格式错误....

但这么看起来,我们还是在面向过程写程序不是么……?而且还要处理并发问题,这synchronized一下,那synchronized一下的,搞不好哪块锁就被提前拿走了;

我最近用exception来处理,发现问题简单了很多
if(Checker.invalidUserName)
  throw new InputException(Constant.INVALID_USER_NAME);
if(Checker.invalidEmail)
  throw new InputException(Constant.INVALID_EMAIL);

然后我们在外面,直接在catch block里做处理;
catch(InpuException){
//do something...
}

这样既保证了我们处理时是synchronized的,又增强了代码的可读性,我想,这应该才是面向对象的设计吧??

47 个解决方案

#1


对不对的好歹来个人……?

#2


说实话 尽量不要用Exception来处理业务相关的东西。。。
不过,有时候 用Exception处理反而比较方便 那就用Exception处理。(这种情况在处理业务层的东西的时候比较多见)
如果,在写基础框架,还是尽量避免。。。。。。

#3


你只是说到Exception的自定义异常,只是Exception的一部分,而我们大多都要继承系统的异常,从而改造成自己所需要的。
而且一个很直观的错误一般也不用异常处理,而对比较不好把握的情况时我们才使用它。

#4


exception将增加对系统资源的开销,所以对于可以预料的错误尽可能判断去解决而不是exception
而且如果考虑到处理多线程,那么只要注意不要设置变量,而设计成方法间的参数传递,就不存在线程间的冲突啦
难道你不能写成
String username = X.getUsername();
String email = X.getEmail();
if(Checker.invalidUserName(username))
  return Constant.INVALID_USER_NAME;
if(Checker.invalidEmail(email))
  return Constant.INVALID_EAMIL;

Checker只包含static的校验方法,接受参数返回boolean就可以啦,这样就不需要synchornized

#5


学习.帮顶.

#6


to: wfeng007(风) 
就是在处理业务时用的exception处理业务,感觉很方便的,基础框架,例如DAO层的CRUD操作我也封了些异常处理进去,例如:
public PO findByPK(long id);
这里在最后做了如下处理:
if(po==null)
   throw new PONotFoundException();
这样的好处就是除BUG更快了,如果某个方法返回一个null,我们不会让它流逝到其他方法体里;


to:jsjzzh(蚯蚓) 
没听懂你说什么,或者是你没仔细看我写的?

to:fdabobi(小爪尖尖) 
增加系统资源的开销?给我个证明,我在看exception这部分的源码时,感觉它只是简单的把一些信息打印到栈里做同步处理,这和我们写一个方法再做些处理有什么不同呢?你这样的写法我上面说过了,和我以前一样,这样也不是不对,但这是面向过程的处理方法,如果是面向对象的处理,你觉的用户输入一个错误格式的用户名对于一个对象来说,是不是异常呢?

#7


exception特别是checked exception会增加程序处理的开销毫无疑义。这个和exception类本身的细节没有关系。

exception就是exception,如果属于你的业务的正常流程,就不能算exception.
用户输入了错误格式,对于用户来说可能是异常,但是对于系统来说却不一定是。

一个可以借鉴的例子是:hibernate以前所有的hibernateException都是checked exception,后来都换成了unchecked exception.

#8


使用checked exception控制流程,性能开销肯定是有的,但是,是不是大的足够影响系统的性能?就我的经验来说,那点开销对系统运行并没有显著的影响。而这样好处显而易见:代码清晰可读,扩展性强。

#9


测试了下,性能的降低还是有的,但象用户注册这类动作,在实际运行中发生的频率很高么?应该还算是可以接受的吧??
  拿hibernateException做例子是不妥的,这就象你写个小方法,总不能这样吧
try{
  //.......
}catch(NullPointerException e){
  //do something.....
}
  天知道你在try里有多少个可以抛出null的地方,hibernate也是如此,随着它体积的增大,天知道你会在一个try里做多少能抛出hibernateException的操作;

#10


采用retcode就是OP,throw Exception就是OO
不知道楼主怎么得出这个结论的?

#11


up

#12


我也有点糊涂了,呵呵~~~~不知当初发贴时是怎么想的,只是觉的以前写的代码中,这样的写法很别扭:
public int operation();

public void process(){
  int operate = operation();
  if(operate==1)
    //do something...
  if(operate==2)
    //do something...
  if(operate==3)
    //do something..
}
  这样的写法,如果别人拿来使,怎么使?模块的可重用性明显不好,由于不是科班出身,我对OO的理解很弱,但我只觉的这样写,和那些机械仪表上的上下拨动的开关控制器一样,如果不给你一份详细的说明,你都不知道他们往上,往下拨动都是在做什么。
  而使用异常则会好很多,起码知道这是一个异常状态,楼上有提到checked exception,所以刚又拿出effective java出来看了看,确实不太应该将流程控制放在catch block里;
  看来还是太浮躁~~~读书不精呀~~~不过在应用里放一些NotFoundUserException也未尝不可吧 ^_^

#13


如果需要这种判断,也只能逐一比较了。你的做法只是把判断转移到catch段而已。
而且用异常控制流程是不建议使用。当然,就事论事,看情况了。

#14


把判断放到catch块只是代码可读性强了不少~~~
public void operation()throws UserNotFoundException,InvalidPwdException;

所以我当初才想这样应该比较好些吧~~?

#15


study.

#16


我是来混分的!

#17


用异常慢,最好是用struts的校验来做,不过,有时候的确需要用异常来处理一些东西。

#18


用异常会让你的代码显得健壮!!!

当然你要快的话...就不要用...事无全美...

#19


使用checked exception控制业务流程还有一个很大的好处:业务异常本身可以携带信息.

#20


晕  乱来

#21


自定义异常好实用的说!
还可以配置一个异常信息.properties

#22


楼上的有点夸张……但思路也不错~~~~ :)

#23


study.

#24


其实当前异常机制还不太好

#25


up

#26


ding#####
ding#####
请问这里可以灌水吗

#27


不推荐用异常处理去实现一些业务逻辑的东西!
至于楼主所说的“用户名格式错误”“密码格式错误”“邮箱格式不正确”之类的,可以采用javascript去实现!
还有struts框架中的验证你可以采用,如果还不能满足你所希望的功能,那你可以看看struts的源代码,然后对其进行修改!
尽量不要用异常去处理业务逻辑的东西!

#28


不过楼主的思想还是不错的!
在某些场合里,楼主的这种方法应该会起到比较积极的作用!

鼓励一下!

我也学习!

#29


up

#30


我一直在考虑一个问题,如果这个系统在不断的扩展,不知道您的系统中将会有多少个Exception的子类...可怕...

    也许您有另一个管理异常类的方法吧...

#31


^_^ "土豆搬家",升得好快呀,就五个三角了!

#32


这也是Anders和James之间的争论
个人认为,在f()->g()->h()->i()这样多层调用,又要根据一层一层返回值分支的程序,不如用异常来的清晰。还有比如你想抛出继承EJBException的异常来让容器回滚。这些情况下异常都是很有用的。
至于楼主的例子,比较简单,其实可以不用。

#33


恩恩~~~现在觉悟到了~~~用exception控制流程不好~~
不过对于Pt_Coffee(Pt.Mr.咖啡)的问题~~~我不同层的exception都是继承这一层的父类异常,如果没有特殊需求,只要在catch块里捕捉这个父类异常就好了~~~

#34


>>恩恩~~~现在觉悟到了~~~用exception控制流程不好~~

不是控制流程,是执行alternative流程,比如你在Rose里面画sequence diagram的时候,一般一个UC至少要有一个80%会被执行的Basic Flow, 这个Basic Flow里面可能有正常的分支,那可以用返回值控制分之流程,但是还有20%的情况,可能会有几种alternative flow, 如果为了这20%的情况写大量的控制代码,那就不如用异常控制流程。
Anders认为不应该有应用程序业务的异常,应该只有Runtime的系统异常,否则改动接口需要异常匹配事件很烦的事情,但是James认为,你可以用异常来清晰你的Basic Flow控制,把alternative flow排除在弹栈抛异常的处理上,所以代码更清晰,而且严格意义的讲,改动接口需要异常匹配是强制要求调用者对可能的alternative flow的注意

个人认为,James的观点更好。异常控制流程是完全可以的,是正确的,但是使用的场景要对。最常见的异常控制流程的例子就是EJB CMT,当你拿到一个业务异常或者系统异常,你需要回滚的时候,不管你的调用多复杂,多少层次,(比如EJB1 -> EJB2 -> EJB3 -> EJB4, 他们如果都是CMT, required)把你的异常封到一个EJBException里抛回去给容器就OK了,EJB的这种使用方式就是一种很经典的方式。

#35


楼主,你的思考已经接近正解了

#36


如果是要自定义异常的话
为什么自己不写个类呢??
当然是只专门处理以你业务有关的~!~

#37


我觉得象你这样的简单的效验就不应该放在服务端拉
就用javascript搞定。

#38


我觉得象你这样的简单的效验就不应该放在服务端拉
就用javascript搞定。

#39


to:DanielYWoo(绿色毒汁) 
进步就是在思考和争论中得到的 :)

TO:den_dyj() 
我从来不信任跑在本地的东西,JS这种东西从来都是防君子不防小人的;

#40


受益匪浅

#41


学习

#42


java里的exception好像用的是堆栈,一进一出是有影响。但是这种异常如果只抛一层两层,应该没有问题,同时程序的结构会很清晰。
比如常用的MVC,也就是在bean里有异常,servlet接一下给错误页,结构很简单,会有什么问题?

#43


javascript校验应该有,能减少服务器的麻烦。同时服务器端也应该校验,因为javascript的校验不可靠

#44


好像孙卫琴在她的struts的书里讲ActionForm时,ActionForm的validate时出的异常就是抛给servlet的。struts这种架构都这样用,咱们怕什么?^_^

虚心请教,说错莫怪

#45


再说,如果你不用Exception,就得有返回值,还得有配套的程序处理它。这样做,不但代码增多结构容易混乱,而且你敢肯定处理的程序消耗的资源就比用exception消耗的小?

当然了,如果你非得抛个10层20层的,另说。^_^

#46


javascript校验应该有,能减少服务器的麻烦。同时服务器端也应该校验,因为javascript的校验不可靠
-------------------------
恩恩,减压才是JS的用途;


再说,如果你不用Exception,就得有返回值,还得有配套的程序处理它。这样做,不但代码增多结构容易混乱,而且你敢肯定处理的程序消耗的资源就比用exception消耗的小?
-----------------------------
我就是被绕烦了。。。

#47


对,用Exception是简单,但是jdk开销大。

#1


对不对的好歹来个人……?

#2


说实话 尽量不要用Exception来处理业务相关的东西。。。
不过,有时候 用Exception处理反而比较方便 那就用Exception处理。(这种情况在处理业务层的东西的时候比较多见)
如果,在写基础框架,还是尽量避免。。。。。。

#3


你只是说到Exception的自定义异常,只是Exception的一部分,而我们大多都要继承系统的异常,从而改造成自己所需要的。
而且一个很直观的错误一般也不用异常处理,而对比较不好把握的情况时我们才使用它。

#4


exception将增加对系统资源的开销,所以对于可以预料的错误尽可能判断去解决而不是exception
而且如果考虑到处理多线程,那么只要注意不要设置变量,而设计成方法间的参数传递,就不存在线程间的冲突啦
难道你不能写成
String username = X.getUsername();
String email = X.getEmail();
if(Checker.invalidUserName(username))
  return Constant.INVALID_USER_NAME;
if(Checker.invalidEmail(email))
  return Constant.INVALID_EAMIL;

Checker只包含static的校验方法,接受参数返回boolean就可以啦,这样就不需要synchornized

#5


学习.帮顶.

#6


to: wfeng007(风) 
就是在处理业务时用的exception处理业务,感觉很方便的,基础框架,例如DAO层的CRUD操作我也封了些异常处理进去,例如:
public PO findByPK(long id);
这里在最后做了如下处理:
if(po==null)
   throw new PONotFoundException();
这样的好处就是除BUG更快了,如果某个方法返回一个null,我们不会让它流逝到其他方法体里;


to:jsjzzh(蚯蚓) 
没听懂你说什么,或者是你没仔细看我写的?

to:fdabobi(小爪尖尖) 
增加系统资源的开销?给我个证明,我在看exception这部分的源码时,感觉它只是简单的把一些信息打印到栈里做同步处理,这和我们写一个方法再做些处理有什么不同呢?你这样的写法我上面说过了,和我以前一样,这样也不是不对,但这是面向过程的处理方法,如果是面向对象的处理,你觉的用户输入一个错误格式的用户名对于一个对象来说,是不是异常呢?

#7


exception特别是checked exception会增加程序处理的开销毫无疑义。这个和exception类本身的细节没有关系。

exception就是exception,如果属于你的业务的正常流程,就不能算exception.
用户输入了错误格式,对于用户来说可能是异常,但是对于系统来说却不一定是。

一个可以借鉴的例子是:hibernate以前所有的hibernateException都是checked exception,后来都换成了unchecked exception.

#8


使用checked exception控制流程,性能开销肯定是有的,但是,是不是大的足够影响系统的性能?就我的经验来说,那点开销对系统运行并没有显著的影响。而这样好处显而易见:代码清晰可读,扩展性强。

#9


测试了下,性能的降低还是有的,但象用户注册这类动作,在实际运行中发生的频率很高么?应该还算是可以接受的吧??
  拿hibernateException做例子是不妥的,这就象你写个小方法,总不能这样吧
try{
  //.......
}catch(NullPointerException e){
  //do something.....
}
  天知道你在try里有多少个可以抛出null的地方,hibernate也是如此,随着它体积的增大,天知道你会在一个try里做多少能抛出hibernateException的操作;

#10


采用retcode就是OP,throw Exception就是OO
不知道楼主怎么得出这个结论的?

#11


up

#12


我也有点糊涂了,呵呵~~~~不知当初发贴时是怎么想的,只是觉的以前写的代码中,这样的写法很别扭:
public int operation();

public void process(){
  int operate = operation();
  if(operate==1)
    //do something...
  if(operate==2)
    //do something...
  if(operate==3)
    //do something..
}
  这样的写法,如果别人拿来使,怎么使?模块的可重用性明显不好,由于不是科班出身,我对OO的理解很弱,但我只觉的这样写,和那些机械仪表上的上下拨动的开关控制器一样,如果不给你一份详细的说明,你都不知道他们往上,往下拨动都是在做什么。
  而使用异常则会好很多,起码知道这是一个异常状态,楼上有提到checked exception,所以刚又拿出effective java出来看了看,确实不太应该将流程控制放在catch block里;
  看来还是太浮躁~~~读书不精呀~~~不过在应用里放一些NotFoundUserException也未尝不可吧 ^_^

#13


如果需要这种判断,也只能逐一比较了。你的做法只是把判断转移到catch段而已。
而且用异常控制流程是不建议使用。当然,就事论事,看情况了。

#14


把判断放到catch块只是代码可读性强了不少~~~
public void operation()throws UserNotFoundException,InvalidPwdException;

所以我当初才想这样应该比较好些吧~~?

#15


study.

#16


我是来混分的!

#17


用异常慢,最好是用struts的校验来做,不过,有时候的确需要用异常来处理一些东西。

#18


用异常会让你的代码显得健壮!!!

当然你要快的话...就不要用...事无全美...

#19


使用checked exception控制业务流程还有一个很大的好处:业务异常本身可以携带信息.

#20


晕  乱来

#21


自定义异常好实用的说!
还可以配置一个异常信息.properties

#22


楼上的有点夸张……但思路也不错~~~~ :)

#23


study.

#24


其实当前异常机制还不太好

#25


up

#26


ding#####
ding#####
请问这里可以灌水吗

#27


不推荐用异常处理去实现一些业务逻辑的东西!
至于楼主所说的“用户名格式错误”“密码格式错误”“邮箱格式不正确”之类的,可以采用javascript去实现!
还有struts框架中的验证你可以采用,如果还不能满足你所希望的功能,那你可以看看struts的源代码,然后对其进行修改!
尽量不要用异常去处理业务逻辑的东西!

#28


不过楼主的思想还是不错的!
在某些场合里,楼主的这种方法应该会起到比较积极的作用!

鼓励一下!

我也学习!

#29


up

#30


我一直在考虑一个问题,如果这个系统在不断的扩展,不知道您的系统中将会有多少个Exception的子类...可怕...

    也许您有另一个管理异常类的方法吧...

#31


^_^ "土豆搬家",升得好快呀,就五个三角了!

#32


这也是Anders和James之间的争论
个人认为,在f()->g()->h()->i()这样多层调用,又要根据一层一层返回值分支的程序,不如用异常来的清晰。还有比如你想抛出继承EJBException的异常来让容器回滚。这些情况下异常都是很有用的。
至于楼主的例子,比较简单,其实可以不用。

#33


恩恩~~~现在觉悟到了~~~用exception控制流程不好~~
不过对于Pt_Coffee(Pt.Mr.咖啡)的问题~~~我不同层的exception都是继承这一层的父类异常,如果没有特殊需求,只要在catch块里捕捉这个父类异常就好了~~~

#34


>>恩恩~~~现在觉悟到了~~~用exception控制流程不好~~

不是控制流程,是执行alternative流程,比如你在Rose里面画sequence diagram的时候,一般一个UC至少要有一个80%会被执行的Basic Flow, 这个Basic Flow里面可能有正常的分支,那可以用返回值控制分之流程,但是还有20%的情况,可能会有几种alternative flow, 如果为了这20%的情况写大量的控制代码,那就不如用异常控制流程。
Anders认为不应该有应用程序业务的异常,应该只有Runtime的系统异常,否则改动接口需要异常匹配事件很烦的事情,但是James认为,你可以用异常来清晰你的Basic Flow控制,把alternative flow排除在弹栈抛异常的处理上,所以代码更清晰,而且严格意义的讲,改动接口需要异常匹配是强制要求调用者对可能的alternative flow的注意

个人认为,James的观点更好。异常控制流程是完全可以的,是正确的,但是使用的场景要对。最常见的异常控制流程的例子就是EJB CMT,当你拿到一个业务异常或者系统异常,你需要回滚的时候,不管你的调用多复杂,多少层次,(比如EJB1 -> EJB2 -> EJB3 -> EJB4, 他们如果都是CMT, required)把你的异常封到一个EJBException里抛回去给容器就OK了,EJB的这种使用方式就是一种很经典的方式。

#35


楼主,你的思考已经接近正解了

#36


如果是要自定义异常的话
为什么自己不写个类呢??
当然是只专门处理以你业务有关的~!~

#37


我觉得象你这样的简单的效验就不应该放在服务端拉
就用javascript搞定。

#38


我觉得象你这样的简单的效验就不应该放在服务端拉
就用javascript搞定。

#39


to:DanielYWoo(绿色毒汁) 
进步就是在思考和争论中得到的 :)

TO:den_dyj() 
我从来不信任跑在本地的东西,JS这种东西从来都是防君子不防小人的;

#40


受益匪浅

#41


学习

#42


java里的exception好像用的是堆栈,一进一出是有影响。但是这种异常如果只抛一层两层,应该没有问题,同时程序的结构会很清晰。
比如常用的MVC,也就是在bean里有异常,servlet接一下给错误页,结构很简单,会有什么问题?

#43


javascript校验应该有,能减少服务器的麻烦。同时服务器端也应该校验,因为javascript的校验不可靠

#44


好像孙卫琴在她的struts的书里讲ActionForm时,ActionForm的validate时出的异常就是抛给servlet的。struts这种架构都这样用,咱们怕什么?^_^

虚心请教,说错莫怪

#45


再说,如果你不用Exception,就得有返回值,还得有配套的程序处理它。这样做,不但代码增多结构容易混乱,而且你敢肯定处理的程序消耗的资源就比用exception消耗的小?

当然了,如果你非得抛个10层20层的,另说。^_^

#46


javascript校验应该有,能减少服务器的麻烦。同时服务器端也应该校验,因为javascript的校验不可靠
-------------------------
恩恩,减压才是JS的用途;


再说,如果你不用Exception,就得有返回值,还得有配套的程序处理它。这样做,不但代码增多结构容易混乱,而且你敢肯定处理的程序消耗的资源就比用exception消耗的小?
-----------------------------
我就是被绕烦了。。。

#47


对,用Exception是简单,但是jdk开销大。