`

异常处理

阅读更多

异常处理。

 

Java中相对过去的程序语言 异常是个很大的特点

 

它有什么好处呢:

写道
没有采用checked exception的后果就是,界面上总是不经意的跳出带有Delphi风格的异常对话框,这就是Delphi程序员和C#程序员的悲哀。程序员也总是搞不清楚自己调用的API有没有抛出异常,总是忘记捕获该捕获的异常

 

而且java强制你进行异常处理。看来是我们java程序身在福中不知福啊。

 

对于java异常  基础知识早已知道,异常的处理,异常的结构。

天天使用,但是如何使用,使用的情况,真是不惨不忍睹。

 

今日早上又听到同事的讨论,在压力测试的时候,注册用户出现了主键冲突问题。

解释是很多用户一起注册的时候,当前一个用户在判断用户名是否已经使用的时候,另一用户进来了,并成功注册了同样的用户名,看似这就是一个线程并发的问题。

但这种现象我想在正常运行下发生的可能性太小了,看了很多系统,没有那个在注册的时候还加个同步吧。

而且在注册前是先会判断的,那么同事的讨论就涉及到了userManager.save方法的返回值问题,

同事A:这个方法要返回一个boolean,才能对其判断是否正确执行。

同事B:那应该抛个异常啊。

这两句话不由想起对异常的处理,怎么处理异常,怎么去设计好的异常结构。当然从上面两句,感觉同事A被面向过程语言害得惨啊。

 

 

如何设计异常,感觉真的是什么时候能理解异常啊,什么时候就能知道什么叫OO了。异常不仅是强制去写个更健壮的程序来,应该更多的是体现了OO思想

 

写道
关于异常作为一种流控制的方法,异常带给我们的好处还是多于坏处,至少使得程序更加健壮。

我设计的login总是使用自定义的异常来控制流程,我不同意在调用前检查环境比如if(!userExist())这样只会加重数据库的访问负担,另外,考虑register方法:

如果定义
if(!userExist(...)) {
if(register(...)==true) {
}
}

哈哈问题出来了:且不说访问了两次数据库,如果刚好检测了if,另一个线程了插入了相同的用户名怎么办?难道用synchronize同步?这样的话效率比使用异常还要大大的降低
 
写道

使用Checked Exception还是UnChecked Exception的原则,我的看法是根据需求而定。

如果你希望强制你的类调用者来处理异常,那么就用Checked Exception;
如果你不希望强制你的类调用者来处理异常,就用UnChecked。

那么究竟强制还是不强制,权衡的依据在于从业务系统的逻辑规则来考虑,如果业务规则定义了调用者应该处理,那么就必须Checked,如果业务规则没有定义,就应该用UnChecked。

还是拿那个用户登陆的例子来说,可能产生的异常有:

IOException (例如读取配置文件找不到)
SQLException (例如连接数据库错误)
ClassNotFoundException(找不到数据库驱动类)

NoSuchUserException
PasswordNotMatchException

以上3个异常是和业务逻辑无关的系统容错异常,所以应该转换为RuntimeException,不强制类调用者来处理;而下面两个异常是和业务逻辑相关的流程,从业务实现的角度来说,类调用者必须处理,所以要Checked,强迫调用者去处理。

在这里将用户验证和密码验证转化为方法返回值是一个非常糟糕的设计,不但不能够有效的标示业务逻辑的各种流程,而且失去了强制类调用者去处理的安全保障。

至于类调用者catch到NoSuchUserException和PasswordNotMatchException怎么处理,也要根据他自己具体的业务逻辑了。或者他有能力也应该处理,就自己处理掉了;或者他不关心这个异常,也不希望上面的类调用者关心,就转化为 RuntimeException;或者他希望上面的类调用者处理,而不是自己处理,就转化为本层的异常继续往上抛出来。
 

对于过去的一个帖子讨论异常使用http://www.iteye.com/topic/2038?page=1

 

写道
在使用UseCase来描述一个场景的时候,有一个主事件流和n个异常流。异常流可能发生在主事件流的过程,而try语句里面实现的是主事件流,而 catch里面实现的是异常流,在这里Exception不代表程序出现了异常或者错误,Exception只是面向对象化的业务逻辑控制方法 。如果没有明白这一点,那么我认为并没有真正明白应该怎么使用Java来正确的编程。

而我自己写的程序,会自定义大量的Exception类,所有这些Exception类都不意味着程序出现了异常或者错误,只是代表非主事件流的发生的,用来进行那些分支流程的流程控制的。例如你往权限系统中增加一个用户,应该定义1个异常类,UserExistedException,抛出这个异常不代表你插入动作失败,只说明你碰到一个分支流程,留待后面的catch中来处理这个分支流程 。传统的程序员会写一个if else来处理,而一个合格的OOP程序员应该有意识的使用try catch 方式来区分主事件流和n个分支流程的处理,通过try catch,而不是if else来从代码上把不同的事件流隔离开来进行分别的代码撰写。
 
写道
另外纠正一个错误的观点:很多人喜欢定义方法的返回类型为boolean型的,当方法正确执行,没有出错的时候返回true,而方法出现出现了问题,返回false。这在Java编程当中是大错而特错的!

方法的返回值只意味着当你的方法调用要返回业务逻辑的处理结果的。如果业务逻辑不带处理结果,那么就是void的,不要使用返回值boolean来代表方法是否正确执行。

例如 用户登陆方法

Java代码

1. boolean login(String username, String password);;

boolean login(String username, String password);;



很多人喜欢用boolean返回,如果是true,就是login了,如果false就是没有登陆上。其实是错误的。还有的人定义返回值为int型的,例如如果正确返回就是0,如果用户找不到就是-1,如果密码不对,就是-2

Java代码

1. int login(String username, String password);;

int login(String username, String password);;




然后在主程序里面写一个if else来判断不同的流程。

Java代码

1. int logon = UserManager.login(xx,xx);;
2. if (logon ==0); {
3. ...
4. } else if (logon == 1); {
5. ...
6. } else if (logon ==2); {
7. ..}

int logon = UserManager.login(xx,xx);;
if (logon ==0); {
...
} else if (logon == 1); {
...
} else if (logon ==2); {
..}



这是面向过程的编程逻辑,不是面向对象的编程逻辑。

应该这样来写:

Java代码

1. User login(String username, String password); throws UserNotFoundException, PasswordNotMatchException;

User login(String username, String password); throws UserNotFoundException, PasswordNotMatchException;



主程序这样来写:

Java代码

1. try {
2. UserManager.login(xx,xx);;
3. ....
4. 用户登陆以后的主事件流代码
5.
6. } catch (UserNotFoundException e); {
7.
8. ...
9.
10. 用户名称没有的事件处理,例如产生一个提示用户注册的页面
11.
12. } catch (PasswordNotMatchException e); {
13.
14. ....
15.
16. 密码不对的事件处理,例如forward到重新登陆的页面
17. }

 对于上面的代码,一些人提出了疑问:

写道
就用用户登陆的例子,那么我得代码要写成这样:
try{
...
}catch(UserexistException e){
}catch(PasswordisEmptyException e){
}catch(UserPasswordNotMatchException e){
}...

这样写与
if(){
}else if(){
}else if(){
}
有什么太多不同吗?而且效率较低。
主流之流的界定是另外一个问题,比如用户注册,一般来说,用户想注册的id一般来说都是被别人先注册了的。那么catch UserexistException的机会将会多于try中的主流的流程,这是一个极端的情况,我只是想说,主流和之流的界定是很模糊。

 不想从效率来说使用异常就说效率低了,不用异常就很高。

对于系统性能的优化,并不是主观意识的,那得通过压力测试,找到性能热点再进行优化。

而且对于优化,很多年前 专家就提出三条经典优化规则:一不优化二还是不优化三确认你是专家再考虑是否优化

更重要的是:不辞劳苦地去优化并不见得就是好的效果,因为你优化的地方可能对于性能热点是个杯水车薪。

 

对于上面的疑问可以用这段来解释:

写道
关键词:不正常、正常

又把前面的帖子看了一遍,感觉是大家对程序控制流程有着不同的看法。在《Effective Java》(中文版)上说“异常只应该被用于不正常的条件,它们永远不应该被永远正常的控制流 ”。
我原先以为那个不是一个程序控制流程,所以我用
try {
User login(...);
} catch (e) {}
来替代
if (login(...)) {}
是正确的。
但实际上那是一个控制流程,只不过用boolean 来实现时变成了不正常的控制流程--不能返回更详细的出错信息。异常不应该被用来控制正常的控制流,但可以用来替换不正常的控制流。

 这个关键词攫取得不错。哈。。

 

对于使用checked exception还是runtimeexception

写道
使用Checked Exception还是UnChecked Exception的原则,我的看法是根据需求而定。

如果你希望强制你的类调用者来处理异常,那么就用Checked Exception;
如果你不希望强制你的类调用者来处理异常,就用UnChecked。

那么究竟强制还是不强制,权衡的依据在于从业务系统的逻辑规则来考虑,如果业务规则定义了调用者应该处理,那么就必须Checked,如果业务规则没有定义,就应该用UnChecked。

还是拿那个用户登陆的例子来说,可能产生的异常有:

IOException (例如读取配置文件找不到)
SQLException (例如连接数据库错误)
ClassNotFoundException(找不到数据库驱动类)

NoSuchUserException
PasswordNotMatchException

以上3个异常是和业务逻辑无关的系统容错异常,所以应该转换为RuntimeException,不强制类调用者来处理;而下面两个异常是和业务逻辑相关的流程,从业务实现的角度来说,类调用者必须处理,所以要Checked,强迫调用者去处理。

在这里将用户验证和密码验证转化为方法返回值是一个非常糟糕的设计,不但不能够有效的标示业务逻辑的各种流程,而且失去了强制类调用者去处理的安全保障。

至于类调用者catch到NoSuchUserException和PasswordNotMatchException怎么处理,也要根据他自己具体的业务逻辑了。或者他有能力也应该处理,就自己处理掉了;或者他不关心这个异常,也不希望上面的类调用者关心,就转化为 RuntimeException;或者他希望上面的类调用者处理,而不是自己处理,就转化为本层的异常继续往上抛出来。

 

对于这个帖子的总结:

写道
异常类层次设计的不好带来的结果就是非常糟糕,例如JTA的异常类层次,例如EJB的异常类层次,但是也有设计的很好的,例如Spring DataAccessException类层次结构。

用设计糟糕的异常类层次来否定异常这个事物,是极度缺乏说服力的,就好像有人用菜刀砍了人,你不能否定这把菜刀一样。

这个帖子这么长了,该讨论的问题都讨论清楚了,总结也总结过n遍了,所以我早就没有兴趣再跟帖了。

实际上,这个讨论中隐含两个不断纠缠的话题:

1、checked ,还是unchecked异常?
2、用自定义的方法调用返回code,还是用异常来表达不期望各种的事件流

经过这么长的讨论,我认为结论已经非常清楚:

1、应该适用unchecked异常,也就是runtimeexception,这样可以让无法处理异常的应用代码简单忽略它,让更上层次的代码来处理

2、应该适用异常来表达不期望的各种事件流

事实上,你们去看一下现在Spring,Hibernate3都已经采用这种方式,特别是Spring的DataAccessException异常层次设计,是一个很好的例子。即使用RuntimeException来表达不期望的各种事件流。

 

对于异常处理,可以放到统一的地方进行处理,比如acegi就是,struts也是,可以看看

写道
采用Exception来处理流程,然后由系统定义统一的异常处理框架,根据异常类名返回配置的信息(客户容易接受的异常信息和开发人员调式使用的触发异常的原因)。这篇文章不错。http://www.onjava.com/pub/a/onjava/2006/01/11/exception-handling-framework-for-j2ee.html?page=6&x-order=date

 

现在struts中的action中,只要抛出异常就可以,在配置文件中配置下,struts就来处理这些异常,跳转到相应页面,显示很友好的提示信息。

分享到:
评论

相关推荐

    Spring Cloud Gateway的全局异常处理

    Spring Cloud Gateway的全局异常处理 Spring Cloud Gateway中的全局异常处理不能直接用@ControllerAdvice来处理,通过跟踪异常信息的抛出,找到对应的源码,自定义一些处理逻辑来符合业务的需求。 网关都是给接口做...

    C#异常处理总结及简单实例

    C#异常处理总结及简单实例 一、异常处理的理解? 异常处理是指程序在运行过程中,发生错误会导致程序退出,这种错误,就叫做异常。 因此处理这种错误,就称为异常处理。 二、异常处理如何操作? C# 异常处理时建立在...

    异常处理.ppt异常处理.ppt异常处理.ppt异常处理.ppt异常处理.ppt

    异常处理.ppt异常处理.ppt异常处理.ppt异常处理.ppt异常处理.ppt异常处理.ppt

    两数计算+异常处理

    课程作业,实现两数计算及其异常处理,异常处理机制能让程序在异常发生时,按照代码的预先设定的异常处理逻辑,针对性地处理异常,让程序尽最大可能恢复正常并继续执行,且保持代码的清晰。 Java中的异常可以是函数...

    精讲RestTemplate自定义请求失败异常处理.docx

    在开始进行自定义的异常处理逻辑之前,我们有必要看一下异常处理的默认实现。也就是:为什么会产生上面小节提到的现象? ResponseErrorHandler是RestTemplate请求结果的异常处理器接口 o接口的第一个方法hasError...

    异常处理 异常处理 异常处理

    关于异常处理的word文档 关于异常处理的word文档 关于异常处理的word文档

    Springboot全局异常处理demo.zip

    Springboot全局异常处理demo 项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的、不可预知的异常需要处理。每个过程都单独处理异常,系统的...

    MySQL定义异常和异常处理详解

    主要为大家详细介绍了MySQL定义异常和异常处理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

    C和C++中的异常处理

    2. Microsoft 对异常处理方法的扩展 3. 标准 C++异常处理的基本语法和语义 4. 实例剖析 EH 5. C++的 new 和 delete 操作时的异常处理 6. Microsoft 对于的实现版本中的异常处理 7. 部分构造及 placement delete 8. ...

    C++ 异常处理 C++ 异常处理

    C++ 异常处理 C++ 异常处理C++ 异常处理C++ 异常处理C++ 异常处理C++ 异常处理C++ 异常处理C++ 异常处理

    java异常处理java异常处理

    java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理

    c/vc++/MFC异常处理/结构化异常处理 浅析

    c/vc++/结构化异常处理 浅析 C语言异常处理 C++语言异常处理 异常处理函数 MFC异常处理 结构化异常处理

    spingmvc+mybatis+统一异常处理机制

    统一异常处理会区分前端是否ajax请求,自动返回json数据格式,要求开发人员在处理ajax请求时统一封装成一个对象返回,以符合代码统一规范。 此工程在idea环境编写,导入请自己新建工程手工复制代码导入。

    易语言线程结构异常处理

    易语言线程结构异常处理源码,线程结构异常处理,SE保护内存读写,除0异常,十到十六,到十六进制文本,汇编_写到内存,指针到EXCEPTION_RECORD结构,指针到CONTEXT结构

    ADS异常处理.pptADS异常处理.pptADS异常处理.ppt

    ADS异常处理.pptADS异常处理.pptADS异常处理.ppt

    ARM异常处理机制ARM异常处理机制

    ARM异常处理机制ARM异常处理机制ARM异常处理机制ARM异常处理机制ARM异常处理机制ARM异常处理机制ARM异常处理机制ARM异常处理机制ARM异常处理机制

    详解SpringCloud Finchley Gateway 统一异常处理

    主要介绍了详解SpringCloud Finchley Gateway 统一异常处理,非常具有实用价值,需要的朋友可以参考下

    工作流系统异常处理实现方法

    中的异常处理问题显得尤为突出[1-3]。传统上将异常处理包含于正常流程中的方法不仅不能 有效的处理各类异常,同时使得整个系统流程复杂化;而完全的人工参与也使得异常处理过 程效率低下,形式极不规范。所以,工作...

    第7章 java异常处理

    第7章 java异常处理

    SQLserver存储过程异常处理.txt

    SQLserver存储过程异常处理

Global site tag (gtag.js) - Google Analytics