锁定老帖子 主题:JAVA异常设计原则
精华帖 (7) :: 良好帖 (6) :: 新手帖 (0) :: 隐藏帖 (1)
|
|
---|---|
作者 | 正文 |
发表时间:2011-01-04
最后修改:2011-01-04
badqiu 写道 不使用异常的人员一直扛着两面大旗:
多数情况下JDK自带的CheckedException,我们都会转化成Unchecked Exception的,如果JDK,如果JDK异常全部都转成Unchecked Exception,异常携带的信息不如我们自己控制更丰富,更灵活。
1. "不要使用异常来控制流程" 2. "性能" LZ的回答很好,回答了异常最主要的功能:分离错误代码和正常代码,代码更简洁。 但至于 checked exceptin,unchedked exceptin. 你就不要再纠结了,统一使用 RuntimeException. checked exception是JAVA最SB的设计. 1. 它要求调用方强制在调用的位置处理异常. 如SQLException, RMI RemoteException,其实调用方也没有任何办法处理异常,只能log或者再包装一次抛出去. 2. 影响接口,如果你的接口已经发布出去,如果想增加异常抛出怎么办呢? 使用checked exceptin要影响客户端的代码,编译都过不了. 所以折衷的办法是在接口声明一个所有的父类异常. 如ant的 BuildException. 并且现在的 J2EE规范也基本不使用 checked exception 一些业务异常还是需要CheckException的,程序要根据不同的异常类型返回给用户不同的信息! 比如说,金币不够的异常,你要告诉用户金币不够,还要明确的告诉他现在所以剩多少金币,还需要多少金币,甚至还引导用户到金币充值流程(页面上让用户作出选择),这些都是Unchecked Exception无法做到的。 当然还有另一种解决方案,实现一个金币是否足够的方法! 用哪种实现方法的依据是“金币不够”是属于异常流程还是正常流程。 |
|
返回顶楼 | |
发表时间:2011-01-04
yanical 写道 luckaway 写道 2. 转账的额度是页面单选框(100、200、300、400、500)选择的: 转账的额度用户不能轻易的更改,但是不排除有些无聊的人会借助其他工具(如,firebug)来修改。此类事件还是占少数的,我们就可以把它归结为非软件bug的异常事件—业务异常(Checked Exception)。 正确的实现如下 不错。不过比较疑惑的还是什么时候用Checked Exception,什么时候用Un-Checked Exception。 一直赞同的一个观点是:只有在客户端可以通过某些手段来弥补发生的错误时才使用Checked Exception。 似乎楼主也支持这个观点?但是我一直没有发现过那个地方可以确定客户端可以弥补错误,包括楼主举的上面这个例子,我觉得这个时候客户端也没法做什么了。而且为了这种小可能做成Checked Exception,让调用的地方都要来处理,好像把代码搞混乱了。 改成Unchecked Exception我们只能提示用户“系统错误”之类的,感觉就是软件bug了。 我个人觉得这种事件,还是可以容忍的,应该给用户一个明确的提示,告诉它不要修改radio值 |
|
返回顶楼 | |
发表时间:2011-01-04
现在看的都有些懵了,按我的理解,不管是Exception及其子类或者RuntimeException及其子类,都是有可能对你的业务逻辑产生影响的,如果你非常坚信你的程序不会出错,当然你不用管它是什么异常,但是如果他影响了你的业务逻辑,对用户的体验产生了负面影响,那你就得去解决,当用户访问资源时出现问题,怎么可能不对产生这样的问题的异常进行处理,不能一味的追求代码上的整洁。
|
|
返回顶楼 | |
发表时间:2011-01-04
最后修改:2011-01-04
Vicent_Lee 写道 现在看的都有些懵了,按我的理解,不管是Exception及其子类或者RuntimeException及其子类,都是有可能对你的业务逻辑产生影响的,如果你非常坚信你的程序不会出错,当然你不用管它是什么异常,但是如果他影响了你的业务逻辑,对用户的体验产生了负面影响,那你就得去解决,当用户访问资源时出现问题,怎么可能不对产生这样的问题的异常进行处理,不能一味的追求代码上的整洁。
是都用进行处理,不可能把异常抛给用户的! 是如何处理的问题,造成运行时异常的原因有很多,比如;数据库连不上,远程地址访问,数据越界,空指针等,这些根据业务是没什么关系的,不可能根据异常类型一一给出不同的提示。可能就是在Action或者一个统一错误处理类,记录错误的日志,然后提示用户“系统错误,请联系管理员”之类的 对这类异常用户是无能为力的 |
|
返回顶楼 | |
发表时间:2011-01-04
joknm 写道 yanical 写道 不要用异常来控制程序的正常流程
LZ一语道破。 最近也很纠结这个问题。 可我们经常用异常来控制程序的正常流程 |
|
返回顶楼 | |
发表时间:2011-01-04
luckaway 写道 badqiu 写道 不使用异常的人员一直扛着两面大旗:
多数情况下JDK自带的CheckedException,我们都会转化成Unchecked Exception的,如果JDK,如果JDK异常全部都转成Unchecked Exception,异常携带的信息不如我们自己控制更丰富,更灵活。
1. "不要使用异常来控制流程" 2. "性能" LZ的回答很好,回答了异常最主要的功能:分离错误代码和正常代码,代码更简洁。 但至于 checked exceptin,unchedked exceptin. 你就不要再纠结了,统一使用 RuntimeException. checked exception是JAVA最SB的设计. 1. 它要求调用方强制在调用的位置处理异常. 如SQLException, RMI RemoteException,其实调用方也没有任何办法处理异常,只能log或者再包装一次抛出去. 2. 影响接口,如果你的接口已经发布出去,如果想增加异常抛出怎么办呢? 使用checked exceptin要影响客户端的代码,编译都过不了. 所以折衷的办法是在接口声明一个所有的父类异常. 如ant的 BuildException. 并且现在的 J2EE规范也基本不使用 checked exception 一些业务异常还是需要CheckException的,程序要根据不同的异常类型返回给用户不同的信息! 比如说,金币不够的异常,你要告诉用户金币不够,还要明确的告诉他现在所以剩多少金币,还需要多少金币,甚至还引导用户到金币充值流程(页面上让用户作出选择),这些都是Unchecked Exception无法做到的。 当然还有另一种解决方案,实现一个金币是否足够的方法! 用哪种实现方法的依据是“金币不够”是属于异常流程还是正常流程。 没搞明白你,难道你 Checked Exception带的信息就比我 UncheckedException信息丰富? 我是说异常体系根本就不需要Checked Exception存在,然后你所要完成的功能全部由 UncheckedException完成。Checked,Unchecked只有在调用处强制处理异常的区别,功能完全是一样的。 举个例子。 我们的servlet要调用你的一个 service方法. @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException { // 现在我只能抛出 ServletException,IOException,抛不出去SomeCheckedException try { someService.execute(); }catch(SomeCheckedException e) { // 你竟然要求我立即在这里 处理异常,连给我通过框架统一处理异常的机会都没有,不SB么? // 所以,因为CheckdException,我在这里只能 log一次,或者是 throw new RuntimeException(e); } } |
|
返回顶楼 | |
发表时间:2011-01-04
badqiu 写道 luckaway 写道 badqiu 写道 不使用异常的人员一直扛着两面大旗:
多数情况下JDK自带的CheckedException,我们都会转化成Unchecked Exception的,如果JDK,如果JDK异常全部都转成Unchecked Exception,异常携带的信息不如我们自己控制更丰富,更灵活。
1. "不要使用异常来控制流程" 2. "性能" LZ的回答很好,回答了异常最主要的功能:分离错误代码和正常代码,代码更简洁。 但至于 checked exceptin,unchedked exceptin. 你就不要再纠结了,统一使用 RuntimeException. checked exception是JAVA最SB的设计. 1. 它要求调用方强制在调用的位置处理异常. 如SQLException, RMI RemoteException,其实调用方也没有任何办法处理异常,只能log或者再包装一次抛出去. 2. 影响接口,如果你的接口已经发布出去,如果想增加异常抛出怎么办呢? 使用checked exceptin要影响客户端的代码,编译都过不了. 所以折衷的办法是在接口声明一个所有的父类异常. 如ant的 BuildException. 并且现在的 J2EE规范也基本不使用 checked exception 一些业务异常还是需要CheckException的,程序要根据不同的异常类型返回给用户不同的信息! 比如说,金币不够的异常,你要告诉用户金币不够,还要明确的告诉他现在所以剩多少金币,还需要多少金币,甚至还引导用户到金币充值流程(页面上让用户作出选择),这些都是Unchecked Exception无法做到的。 当然还有另一种解决方案,实现一个金币是否足够的方法! 用哪种实现方法的依据是“金币不够”是属于异常流程还是正常流程。 没搞明白你,难道你 Checked Exception带的信息就比我 UncheckedException信息丰富? 我是说异常体系根本就不需要Checked Exception存在,然后你所要完成的功能全部由 UncheckedException完成。Checked,Unchecked只有在调用处强制处理异常的区别,功能完全是一样的。 举个例子。 我们的servlet要调用你的一个 service方法. @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException { // 现在我只能抛出 ServletException,IOException,抛不出去SomeCheckedException try { someService.execute(); }catch(SomeCheckedException e) { // 你竟然要求我立即在这里 处理异常,连给我通过框架统一处理异常的机会都没有,不SB么? // 所以,因为CheckdException,我在这里只能 log一次,或者是 throw new RuntimeException(e); } } 这个可以在service层就把异常都处理掉吧。如果这个checked的异常是很无聊的一个异常的话只能说是设计上面的问题,不能说是checked异常的问题。checked异常的用处不就是告诉你我这里可能会出错么,如果都是runtime的话对于其他人连你可能会有哪些异常都不知道啊。 |
|
返回顶楼 | |
发表时间:2011-01-04
badqiu 写道 没搞明白你,难道你 Checked Exception带的信息就比我 UncheckedException信息丰富? 我是说异常体系根本就不需要Checked Exception存在,然后你所要完成的功能全部由 UncheckedException完成。Checked,Unchecked只有在调用处强制处理异常的区别,功能完全是一样的。 举个例子。 我们的servlet要调用你的一个 service方法. @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException { // 现在我只能抛出 ServletException,IOException,抛不出去SomeCheckedException try { someService.execute(); }catch(SomeCheckedException e) { // 你竟然要求我立即在这里 处理异常,连给我通过框架统一处理异常的机会都没有,不SB么? // 所以,因为CheckdException,我在这里只能 log一次,或者是 throw new RuntimeException(e); } } 如果仅仅是记录错误日志或者throw new RuntimeException(e),是没必用Checked Exception。JDK的Checked Exception,如:SqlException、UnsupportedEncodingException ,我们都是简单的封装成runtime Exception,也不会增加额外的信息,这种场景下,确实不应该是Checked Exception。 Unchecked Exception和Checked Exception都能携带信息,Unchecked Exception里携带的信息只会给日志记录用。 Checked Exception携带信息更多的作用是给用户看的,甚至有可能都不记录日志了。 public String execute() { try { userService.transferCoin(coin); } catch (CoinNotEnoughException e) { context.put("errorMessage", "你目前的金币是" + e.getTotalCoin() + ",无法转账" + e.getForTransferCoin()); } return SUCCESS; } |
|
返回顶楼 | |
发表时间:2011-01-04
最后修改:2011-01-04
luckaway 写道 badqiu 写道 没搞明白你,难道你 Checked Exception带的信息就比我 UncheckedException信息丰富? 我是说异常体系根本就不需要Checked Exception存在,然后你所要完成的功能全部由 UncheckedException完成。Checked,Unchecked只有在调用处强制处理异常的区别,功能完全是一样的。 举个例子。 我们的servlet要调用你的一个 service方法. @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException { // 现在我只能抛出 ServletException,IOException,抛不出去SomeCheckedException try { someService.execute(); }catch(SomeCheckedException e) { // 你竟然要求我立即在这里 处理异常,连给我通过框架统一处理异常的机会都没有,不SB么? // 所以,因为CheckdException,我在这里只能 log一次,或者是 throw new RuntimeException(e); } } 如果仅仅是记录错误日志或者throw new RuntimeException(e),是没必用Checked Exception。JDK的Checked Exception,如:SqlException、UnsupportedEncodingException ,我们都是简单的封装成runtime Exception,也不会增加额外的信息,这种场景下,确实不应该是Checked Exception。 Unchecked Exception和Checked Exception都能携带信息,Unchecked Exception里携带的信息只会给日志记录用。 Checked Exception携带信息更多的作用是给用户看的,甚至有可能都不记录日志了。 public String execute() { try { userService.transferCoin(coin); } catch (CoinNotEnoughException e) { context.put("errorMessage", "你目前的金币是" + e.getTotalCoin() + ",无法转账" + e.getForTransferCoin()); } return SUCCESS; } 如你自己的demo,你的调用方一定需要强制处理该异常了。 已经没有办法使用框架来处理异常。 你的Checked Exception只是你自己一厢情愿的认为按你现在的方式处理。 难道其它语言没有 Checked Exception就不用活了。 硬按你这种规则区分。 SqlException,UnsupportedEncodingException, DateFormat ParseException 都是JDK败笔,已经懒得说了。 我一直所说使用Checked Exception最主要的缺点: 接口污染,强制调用者立即处理。 所以不用跟我说 Exception转换为message的程序了. 因为要转换为消息的时候,我也直接处理CoinNotEnoughException 这个RuntimeException. 而不是Checked Exception |
|
返回顶楼 | |
发表时间:2011-01-04
joknm 写道 yanical 写道 不要用异常来控制程序的正常流程
LZ一语道破。 最近也很纠结这个问题。 我一般是用来控制业务流程 |
|
返回顶楼 | |