论坛首页 Java企业应用论坛

老掉牙的话题,java的异常处理。

浏览 36559 次
精华帖 (1) :: 良好帖 (6) :: 新手帖 (12) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-03-18  
有checked你可以默认所有没异常申明的函数都是ok的,除了那些申明自己要抛的不用太关心那些没申明的
你使用api是不可能每个都去看文档的
我原来之所以会在dao采取这种方式因为我认为每个dao函数都应该有抛异常的可能,用check的话上层调用写起来太罗嗦,尤其再加个接口,实际spring的dao也是这样处理
而实际普遍考虑,大部分api是不应该我们操心问题的,如果有异常声明,则我们只用关注这些少量的问题点
如果全部都runtime那我们就要考虑每个调用可能造成的中断,每个api我都要参考它的文档关于异常的描述
另外一旦调用链拉长,a->d的文档是不会都那么全面和可靠,因为抛异常的可能性会随链的长度相乘
0 请登录后投票
   发表时间:2011-03-19  
carlkkx 写道
我认为关于Checked exceptions 已经尘埃落定,结论就是:Checked exceptions是失败的设计。C#放弃这个不是没有道理的。


曾经我也是这样认为,但现在。。。

举两个例子:
在Swing/Awt编程环境中,设计方法抛出IOException意味着这是一个耗时操作,编写EDT安全程序就会相对容易很多:不catch编译器会提示你,强迫你使用SwingWorker等其他手段。桌面程序中所有与IO相关甚至耗时的计算方法抛出IOException已经是一个最佳实践了。

利用Checked Exception做业务流程分支设计比用返回值个人感觉更优雅:编译器会帮你把所有可能分支条件处理好,多一条不行少一条也不行,用返回值的话很可能会有遗漏,对方法使用者不友好。

0 请登录后投票
   发表时间:2011-03-19  
pufan 写道
carlkkx 写道
我认为关于Checked exceptions 已经尘埃落定,结论就是:Checked exceptions是失败的设计。C#放弃这个不是没有道理的。


曾经我也是这样认为,但现在。。。

举两个例子:
在Swing/Awt编程环境中,设计方法抛出IOException意味着这是一个耗时操作,编写EDT安全程序就会相对容易很多:不catch编译器会提示你,强迫你使用SwingWorker等其他手段。桌面程序中所有与IO相关甚至耗时的计算方法抛出IOException已经是一个最佳实践了。

利用Checked Exception做业务流程分支设计比用返回值个人感觉更优雅:编译器会帮你把所有可能分支条件处理好,多一条不行少一条也不行,用返回值的话很可能会有遗漏,对方法使用者不友好。


这正是carlkkx反对的原因。
0 请登录后投票
   发表时间:2011-03-19  
在Swing/Awt编程环境中,设计方法抛出IOException意味着这是一个耗时操作,编写EDT安全程序就会相对容易很多:不catch编译器会提示你,强迫你使用SwingWorker等其他手段。桌面程序中所有与IO相关甚至耗时的计算方法抛出IOException已经是一个最佳实践了。
————————————————————————
我是用Swing开发过还算比较大的软件的,居然一个方法是否耗时需要IOException来表征,这不得不说是一个悲哀。
0 请登录后投票
   发表时间:2011-03-19  
利用Checked Exception做业务流程分支设计比用返回值个人感觉更优雅
——————————————————————
晕倒,这已经是完全滥用异常了,程序执行的正常结果也用异常来表征了,如果我是调用者碰到这样的API我应该是难受死还哪来的优雅。
0 请登录后投票
   发表时间:2011-03-19  
什么是异常?如果我正确完成任务,这个正确完成的结果表示断不会用异常表示,只有不能正确完成任务我才抛出异常表示我无法达到目的。
0 请登录后投票
   发表时间:2011-03-19  
ppgunjack 写道
有checked你可以默认所有没异常申明的函数都是ok的,除了那些申明自己要抛的不用太关心那些没申明的
你使用api是不可能每个都去看文档的
我原来之所以会在dao采取这种方式因为我认为每个dao函数都应该有抛异常的可能,用check的话上层调用写起来太罗嗦,尤其再加个接口,实际spring的dao也是这样处理
而实际普遍考虑,大部分api是不应该我们操心问题的,如果有异常声明,则我们只用关注这些少量的问题点
如果全部都runtime那我们就要考虑每个调用可能造成的中断,每个api我都要参考它的文档关于异常的描述
另外一旦调用链拉长,a->d的文档是不会都那么全面和可靠,因为抛异常的可能性会随链的长度相乘

大多复杂性就是通过分而治之解决的,你非要担心你所面临的API以外的东西,那有什么办法呢?这样担心那就有太多担心了,这样的话,集成电路OK不OK那也是担心的。
0 请登录后投票
   发表时间:2011-03-19  
碰到让强制try catch的,就throw new RuntimeException(e);
个人观点:
如果不是特定的Exception(自定义的业务中的Exception),尽量不要直接throw出来。
0 请登录后投票
   发表时间:2011-03-19   最后修改:2011-03-19
carlkkx 写道
ppgunjack 写道
当a库依赖b库,你调用a库,如果b库全是RuntimeException,并且你拿不到b库文档,你用a库能写出健壮的代码是不可能的,你自己精心构建的异常处理逻辑能轻松被无法预见的RuntimeException打断,因为你预计不到a库什么时候会被b库的雷给牵连,任何对a的调用都要考虑可能由b导致的连环雷
把代码比作做事,RuntimeException就相当于天灾人祸,意外之外的,至于发生了你愿意自己继续干还是终止取决于你自己意愿
而checked就是说你需要弄清楚并且汇报给上级那些是问题,那些是你会遇到但你解决不了的,但都是你意识到的问题,别人让你做事,你要给别人说好,如果让我干可能出现意外1,2,3,怎么处理你自己决定

调用链是a->b->c->d,如果d是没任何这种提前约定的契约,那么a要操心的就是调用b的所有接口,b随时也有可能被c的调用打断,而c随时会被d打断,看似编码简单,实际异常处理被大幅扩大

最简单的例子,你老板让你干活都需要先分析风险,你可能会让底下再分析,然后汇报,然后才是每层自己根据汇报的风险制定计划和执行

如果全unchecked相当于你没任何汇报,只是告诉上级,你让我干事有风险,干什么事都有风险也可能都没风险,你分配我任务的时候自己看着办,还有我下属的风险我可能也转给你也可能不给你我自己搞定,这看我自己风格,你也自己看着办吧

你只跟a有关系,如果a的描述中没有那是a的问题,照你这么说你做每一件事都是寻根问底,否则就不存在安全性了,那封装就没有意义了,因为每一层API你都要看到底,否则你心中没有底。


我觉得 你说来说去 就2个问题
1.使用checkedException会导致乱吞异常
2.不乱吞异常就强制throws会导致接口丑陋

你的建议是 全部RuntimeException 然后在方法注释中写明会抛出什么样的异常


这里面有些奇怪的逻辑
首先 乱吞异常的肯定是213的程序员,既然是213那他会注意调用方法的注释吗? 或者他会写清楚他的注释吗?

其次 有些异常以后的操作是统一的,比如数据库回滚,这些完全不需要调用者干预,这种异常就应该定义成RuntimeException,但是,比如读取一个默认的配置文件,如果配置文件不存在就生成一个默认的.这种完全是应该调用者处理的,而且他有能力处理的,这种就应该抛出checkedException,强制他去处理.免得他忘记了.

0 请登录后投票
   发表时间:2011-03-19  
qianhd 写道
carlkkx 写道
ppgunjack 写道
当a库依赖b库,你调用a库,如果b库全是RuntimeException,并且你拿不到b库文档,你用a库能写出健壮的代码是不可能的,你自己精心构建的异常处理逻辑能轻松被无法预见的RuntimeException打断,因为你预计不到a库什么时候会被b库的雷给牵连,任何对a的调用都要考虑可能由b导致的连环雷
把代码比作做事,RuntimeException就相当于天灾人祸,意外之外的,至于发生了你愿意自己继续干还是终止取决于你自己意愿
而checked就是说你需要弄清楚并且汇报给上级那些是问题,那些是你会遇到但你解决不了的,但都是你意识到的问题,别人让你做事,你要给别人说好,如果让我干可能出现意外1,2,3,怎么处理你自己决定

调用链是a->b->c->d,如果d是没任何这种提前约定的契约,那么a要操心的就是调用b的所有接口,b随时也有可能被c的调用打断,而c随时会被d打断,看似编码简单,实际异常处理被大幅扩大

最简单的例子,你老板让你干活都需要先分析风险,你可能会让底下再分析,然后汇报,然后才是每层自己根据汇报的风险制定计划和执行

如果全unchecked相当于你没任何汇报,只是告诉上级,你让我干事有风险,干什么事都有风险也可能都没风险,你分配我任务的时候自己看着办,还有我下属的风险我可能也转给你也可能不给你我自己搞定,这看我自己风格,你也自己看着办吧

你只跟a有关系,如果a的描述中没有那是a的问题,照你这么说你做每一件事都是寻根问底,否则就不存在安全性了,那封装就没有意义了,因为每一层API你都要看到底,否则你心中没有底。


我觉得 你说来说去 就2个问题
1.使用checkedException会导致乱吞异常
2.不乱吞异常就强制throws会导致接口丑陋

你的建议是 全部RuntimeException 然后在方法注释中写明会抛出什么样的异常


这里面有些奇怪的逻辑
首先 乱吞异常的肯定是213的程序员,既然是213那他会注意调用方法的注释吗? 或者他会写清楚他的注释吗?

其次 有些异常以后的操作是统一的,比如数据库回滚,这些完全不需要调用者干预,这种异常就应该定义成RuntimeException,但是,比如读取一个默认的配置文件,如果配置文件不存在就生成一个默认的.这种完全是应该调用者处理的,而且他有能力处理的,这种就应该抛出checkedException,强制他去处理.免得他忘记了.


你这里忽略一个非常重要的问题,乱吞异常严重性比不处理还要严重,在系统的顶层设置一个未处理异常捕获器,如果有异常到这里,可以提示以及退出系统等。但如果乱吞的话,程序可能已经无法达到预期效果了,但是却没有任何错误报告。这使得系统处于最不友好的状态。
我现在假设一个系统所有的人都没考虑处理任何异常,全部只按正常流程写,即使某些地方确实需要捕获并且处理的,那么经过几次迭代测试之后很多被顶层未处理异常捕获的异常就去查那一个层本来要处理的却没有处理,通过这种方式系统逐步改进也会比充满了乱吞异常代码的系统好很多,因为异常能够报告出来比埋了的好很多。而且我举得是极端例子。不过在
没有很多checkedException扰乱视听下代码会写的很轻松,即使非常一般的程序员犯错误的机会反而小,事后通过多次迭代测试把系统的可靠性逐步完善起来。在各个线程的顶部都要有未处理异常捕获器,要保证系统不能无声无息崩溃。当然如果虚拟机或操作系统崩溃了那自然是另当别论。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics