转:什么时候要抛出异常?

转自:http://blog.csdn.net/tengxiaoming/article/details/5584639

在编写代码的过程中,经常会遇到这样的选择,检查到一个不正常的情况,或者某个操作失败,或者检测到
某个异常,此后该怎么办?是抛出一个异常?还是放回一个表示操作失败的返回值。

=== 两种方式的不同 ===

× 返回值很容易被检测,而捕获异常的代码则相对比较长
    × 抛出以及捕获异常需要更多的系统开销
    × 如果忽略返回值,调用者可以继续,但没有捕获的异常则将终止调用者的执行

=== 应该抛出异常的几种情况 ===
在这些情况下,应该是要抛出异常的:

=== 无法通过参数检查 ===
    
    例如空值、参数取值范围等,因为参数的规则说明是作为方法签名的一部分发布的,调用者应该很清楚
    调用这个方法所需要的参数的规格,但是调用者现在传入的错误的参数,说明调用者本身这时候很可能
    就已经出现问题了。
    
    对参数进行检查本身也是一个编写一个方法的良好习惯,这可以保证方法本身在一个相对比较稳定可知
    道状态下工作,因此方法本身将更简单也更稳定。
    
    总之,拒绝非法的参数,并抛出异常。

=== 将可能导致以后的相关功能出错 ===
    
    如果一个异常或者错误的参数将导致以后更多的异常或者以后的某个功能异常,那么不要延迟,立即抛
    出异常。

例如有一个属性 Filename 用来保存将被保存的文件的名称,一个的方法 Save 将保存到 Filename 所
    指定的文件名中去,显然在给 Filename 属性赋值时,如果给出一个包含非法文件名字符的字符串,那
    么将导致 Save 方法中会有异常发生,不论 Save 方法是否对 Filename 再进行检查,这时候距离设定 
    Filename 的代码可能已经相当远了,因此在设定 Filename 的时候,就应该要进行这种有关的检查,
    如果文件名不合法,立即抛出异常,而不要等到以后再来发现这个问题。
    
    上述对参数进行检查其实很多也是这种情况,特别一些空值参数,将可能导致以后使用该参数的时候发
    生空值异常。
    
    
=== 不应该抛出异常的几种情况 ===
    === 不影响程序继续运行 ===
    
    如果一个错误并不影响程序逻辑的正确性,或者不影响此后代码的继续运行,那么可以不必抛出异常。
    
    一个典型的例子例如,从集合中删除指定键值对应的元素,但指定的键值其实并不在集合中,这显然是
    一个意外情况,但是,就此继续下去,以后的程序应该还可以继续有效的运行,因为即使在正常情况下
    也不过是这个元素不再存在于集合中而已。返回一个整数值表示删除掉的元素的个数,如果没有找到给
    定的元素,则返回0表示没有元素被删除。这个例子的另一种情形是,当前集合元素因为某种原因被锁住
    不能删除元素,那么应该抛出一个异常表示删除失败,而不是返回0表示没有删除元素。
    
别人评论:

非常赞同。 
对于这种难以明确界定的问题,一方面有大原则,但有时候还需要视实际情况酌情处理。“将可能导致以后的相关功能出错”,我的理解是这样的:对于一定导致以后出错的情况,决定抛出异常——因为一个出错的软件接下来只能产生负面功效;对于可能出错也可能不错的情况,可以延迟抛出异常,在真正碰到错误时应该有更高层的异常捕捉,甚至平台——因为抛出异常是有代价的,如果在有希望的时候马上带来损失,相信有时候不可取,而如果不抛出异常会带来更大损失,也许就立即抛出了。总之,我觉得软件的稳定性要求不同,选择是有区别的。这也许是程序员的抉择——但最终是需求的抉择。 
方法始终对参数有效性进行检测——真的很重要。 
很多时候,大家想到了异常,在怎样抛出异常的话题下面,怎么详细地定义可预见的异常、尽量避免异常产生的损失、尽量修复和弥补,是一个稳定健壮软件必须做好的事情。

时间: 2024-10-20 17:21:07

转:什么时候要抛出异常?的相关文章

爱上MVC~业务层刻意抛出异常,全局异常的捕获它并按格式返回

对于业务层的程序的致命错误,我们一直的做法就是直接抛出指定的异常,让程序去终断,这种做法是对的,因为如果一个业务出现了致命的阻塞的问题,就没有必要再向上一层一层的返回了,但这时有个问题,直接抛异常,意味着服务器直接500了,前端如何去显示,或者如果你是API的服务,如果为前端返回,如果是500,那直接就挂了,哈哈! 下面是在MVC环境下优化的全局异常捕获代码(非API) /// <summary> /// 全局异常捕获 /// </summary> public class Glo

拦截404页面时tomcat抛出异常: org.apache.shiro.UnavailableSecurityManagerException

404页面中包含shiro标签,当访问404页面时,抛出异常: 原因:shiro拦截器配置缺少 标红部分,缺少红色部分导致在serverlet在拦截404页面的时候没有经过shiro  从而使shiro标签解析失败引发错误. <filter-mapping>    <filter-name>shiroFilter</filter-name>    <url-pattern>/*</url-pattern> <dispatcher>RE

Java中的异常处理:何时抛出异常,何时捕获异常?

1.如果方法声明名里面有throws异常,那么方法体里面可以不抛出异常.因为可以在方法声明中包含异常说明,但实际上却不抛出!这样做的好处是,为异常先占个位置,以后就可以抛出这种异常而不用修改修改已有的代码.在定义抽象基类和接口时这种能力很重要,这样派生类或接口实现类就能够抛出这些预先声明的异常. 2.为什么有的方法声明里面没有throws,但方法体里面却抛出了异常?从RuntimeException继承的异常,可以在没有异常说明throws的情况下被抛出!对于Runtime异常(也称为非检查的异

throws和throw抛出异常的使用规则

一直对java中的throws和throw不太理解.最近一直在查这两个方面的资料,算是能明白一点吧.如果我下面的观点哪有不对,希望指出来,我加以改进. throw:(针对对象的做法) 抛出一个异常,可以是系统定义的,也可以是自己定义的.下面举两个例子: 抛出Java中的一个系统异常: public class One { public void yichang(){ NumberFormatException e = new NumberFormatException(); throw e; }

winform程序一启动抛出异常--调用目标发生异常

在本机测试没有问题,可一到别的电脑上就抛出异常,这是最麻烦的事,一时间还找不出什么原因,本机上还无法重现. 现在好了,终于找到一个完美解决的办法,在Program.cs类中加入如下代码 static void Main() { Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); Application.Run(new FrmMai

《Effective C 》资源管理:条款25--考虑写出一个不抛出异常的swap函数

条款25考虑写出一个不抛出异常的swap函数 条款25:考虑写出一个不抛出异常的swap函数 swap是STL中的标准函数,用于交换两个对象的数值.后来swap成为异常安全编程(exception-safe programming,条款29)的脊柱,也是实现自我赋值(条款11)的一个常见机制.swap的实现如下: namespace std{ template<typename T> void swap(T& a, T& b) { T temp(a); a=b; b=temp;

构造函数、析构函数抛出异常的问题

构造函数可以抛出异常. C++标准指明析构函数不能.也不应该抛出异常. 那么如果对象在运行期间出现了异常,C++异常处理模型有责任清除那些由于出现异常所导致的已经失效了的对象(也即对象超出了它原来的作用域),并释放对象原来所分配的资源, 这就是调用这些对象的析构函数来完成释放资源的任务,所以从这个意义上说,析构函数已经变成了异常处理的一部分. 上面的论述C++异常处理模型它其实是有一个前提假设——析构函数中是不应该再有异常抛出的.试想,如果对象出了异常,现在异常处理模块为了维护系统对象数据的一致

第10章-异常处理 --- 使用throw抛出异常

第10章-异常处理 --- 使用throw抛出异常 (一)抛出异常 如果需要在程序中自行抛出异常,则应使用throw语句,throw语句可以单独使用,throw语句抛出的不是异常类,而是一个异常实例,而且每次只能抛出一个异常实例. throw语句的语法格式如下: throw ExceptionInstance; 如果throw语句抛出的异常是Checked异常,则该throw语句要么处于try块里,显示捕获该异常,要么放在一个带throws声明抛出的方法中,即把该异常交给该方法的调用者处理;如果

iOS 捕获未知方法的调用,避勉抛出异常

太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS.Android.Html5.Arduino.pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. NSObject 对象是 Objecitve-C 中的根类,其有以下两个方法,在调用 NSObject 及其子类的方法不存在时,会将这个调用封装成

XCode调试的 Stack Trace,调试时抛出异常,定位到某一行代码,并且添加变量监视

在Xcode调试程序的时候,总是会出现不知道错误在什么地方的问题,很是捉急,现在又一个办法,可以具体定位到错误行的代码,试一下吧?超级好用 操作很简单: 1.在XCode界面中直接点击选项卡,跳到Breakpoint的tab 2.然后点击左下角的+号,增加一个Exception的断点,如下图所示. 3.接下来会出现一个"All Exception"的调试选项: 4.将鼠标放到上面,右击选择"Edit Breakpoint",可以查看选项的具体内容如下:(不用做任何修