`

异常处理

阅读更多

异常处理。

 

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就来处理这些异常,跳转到相应页面,显示很友好的提示信息。

分享到:
评论

相关推荐

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

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

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

    MySQL中的异常处理是数据库编程中不可或缺的一部分,它允许开发者预设对可能出现的错误或异常的响应,从而确保程序的稳定性和健壮性。在MySQL中,异常定义和处理主要是通过`DECLARE`语句来实现的。 1. **异常定义**...

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

    异常处理是编程中的一种机制,用于捕获和处理运行时发生的错误或异常情况。异常可以由硬件引发,如硬件异常,也可以由操作系统或应用程序自身触发,即软件异常。当异常发生时,操作系统允许程序有机会检查异常类型并...

    易语言线程结构异常处理

    在易语言中,线程是并发执行的程序单位,线程结构异常处理是编程过程中非常重要的一环,因为线程可能会遇到各种异常情况,如内存访问错误、除零异常等。 线程结构异常处理源码是易语言中处理这些异常的关键部分。当...

    java异常处理习题

    Java 异常处理习题 Java 异常处理是 Java 编程语言中的一种重要机制,用于处理程序在运行时可能出现的错误或异常情况。下面是关于 Java 异常处理的习题和知识点总结: 一、Java 异常处理关键字 * Java 中用来抛出...

    易语言HOOK异常处理

    "New_SE_Handler"可能是一个新的结构化异常处理程序,结构化异常处理(SEH)是Windows操作系统中的一个特性,用于处理硬件和软件异常。 "GetSeAddr"可能是获取异常发生时的地址函数,这对于分析异常原因和定位问题...

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

    在编程领域,异常处理是确保程序健壮性与稳定性的关键技术。对于C、C++以及基于MFC(Microsoft Foundation Classes)的开发来说,异常处理更是不可或缺的一部分。本篇文章将深入浅析C、C++中的异常处理机制以及MFC中...

    详解SpringCloud Finchley Gateway 统一异常处理

    详解 SpringCloud Finchley Gateway 统一异常处理 SpringCloud Finchley Gateway 统一异常处理是指在使用 SpringCloud Finchley 版本的 Gateway 时,如何统一处理系统级异常的方法。默认情况下,SpringCloud ...

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

    【异常处理】是编程中必不可少的一个环节,尤其是在Java这样的面向对象语言中。异常处理机制使得程序在遇到错误时能够优雅地中断执行流程,提供错误信息,并有机会进行恢复操作,而不是简单地崩溃。以下是对异常处理...

    异常处理机制知识点小总结

    异常处理是Java编程中至关重要的一个概念,它确保了程序在遇到错误或异常情况时能够以优雅的方式继续执行或者终止。下面是对Java异常处理机制的详细解析。 在Java中,异常是程序运行时发生的错误,它中断了正常的...

    ARM处理器异常处理步骤

    ARM处理器异常处理是指ARM微处理器对各种异常情况作出响应和处理的过程。异常指的是处理器在正常执行程序时遇到的特殊情况,例如外部中断请求、未对齐的内存访问错误、指令预取终止等。为了保证系统的稳定性和正确性...

    Power builder9异常处理

    在 PowerBuilder 9(简称 PB9)开发过程中,异常处理是一项关键的技术,它能帮助开发者有效地管理和解决程序中出现的错误,确保系统的稳定运行。在实际应用中,开发者经常会遇到各种预知和不可预知的问题,如系统级...

    游标和异常处理 游标和异常处理

    游标和异常处理 游标是 SQL 的一个内存工作区,由系统或用户以变量的形式定义。游标的作用就是用于临时存储从数据库中提取的数据块。在某些情况下,需要把数据从存放在磁盘的表中调到计算机内存中进行处理,最后将...

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

    《ADS异常处理详解》 异常处理是嵌入式系统中至关重要的部分,特别是在基于ARM架构的系统中。本文将深入探讨ARM处理器的异常处理机制,包括异常类型、处理流程、异常优先级以及向量表等内容。 一、异常类型 ARM...

    java实验报告4-异常处理

    Java异常处理是编程中至关重要的一个环节,它确保了程序在遇到错误时能够优雅地运行,而不是突然崩溃。本实验报告“java实验报告4-异常处理”旨在帮助初学者掌握Java中的异常处理机制,以及如何利用log4j进行日志...

    reactnative异常处理库

    React Native 异常处理库是专门为在React Native框架下开发的混合移动应用提供错误管理和调试支持的工具。React Native允许开发者使用JavaScript编写原生移动应用,但JavaScript代码的运行环境中可能会遇到各种错误...

    Spring Cloud Gateway的全局异常处理

    ### Spring Cloud Gateway全局异常处理详解 #### 一、引言 在微服务架构中,网关作为服务入口,承担着路由转发、限流熔断、鉴权认证等职责。Spring Cloud Gateway作为一款基于Spring Framework 5、Project Reactor...

    两数计算+异常处理

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

Global site tag (gtag.js) - Google Analytics