关于异常抛出机制

来源:互联网 发布:网络棋牌游戏能作弊吗 编辑:程序博客网 时间:2024/05/21 18:44

****************try catch使用*********************************************************************
try{
//1:抛出异常的代码
//2:代码
}catch(){
//3:代码
//4:抛出异常
}finally{
//5:代码
}
//6:代码
首先要明确的一点是:不管try是否抛出异常,finally语句块都会执行。
小心注意6!!

整个try,catch,finally执行有以下几种情况:

1:try语句块没有抛出异常。如果是这种情况,程序会执行try,finally以及finally块之后的代码;

2:try语句块抛出了异常并且catch有匹配的异常。当遇到try里面抛出的异常后,try块里面剩下的代码就不执行了,跳转到catch块里面。

这里又可以分为2种情况。第一种,抛出的异常被后面的catch捕获,而catch又没有抛出新的异常,那么执行顺序是1356 ;第二种,如果catch里面又抛出新的异常,顺序是1345,然后将新的异常返回给方法调用者,6就不执行了 ;

3:try语句块抛出了异常,但是后面的catch没有能匹配的异常。那么会执行try和finally里面的语句也就是15,然后将该异常返回给方法调用者,不执行6 。
总结:
如果异常不能被捕捉的话,finally{}后面的语句就不会执行了,而finally{}一定被执行
****************try catch代码中使用*******************************************************************
@try{

}  @catch(NSException *exception) {      NSLog(@"exception:%@", exception);  }  @finally {  }

****************代码异常抛出机制对比******************************************************************
1.ios中很少用到try 和catch,Apple虽然同时提供了错误处理(NSError)和异常处理(exception)两种机制,但是Apple更加提倡开发者使用NSError来处理程序运行中可恢复的错误。而异常被推荐用来处理不可恢复的错误。

原因有几个,在非gc情况下,exception容易造成内存管理问题(文档有描述即使是arc下,也不是安全的);exception使用block造成额外的开销,效率较低等等,另外这也的确是Cocoa开发者的习惯
2.Objective-C 虽然有 @try/@catch,苹果的范例代码中却很少使用到它(至少是在 iOS 部分),苹果对 try/catch 的态度也是限制用在「programming or unexpected runtime errors」[5],像在 Java 里那样用 try/catch 在 Obj-C 中完全行不通。而且 Obj-C 可能出现的异常也不是全都能由 NSException 代表,有些异常必须在 C 级别 trap。总之,try/catch 不是苹果鼓励的开发范式,Cocoa 程序员也极少用它,甚至你会觉得苹果开发者们对 exception 的态度就是「反正也不知道该怎么处理索性就让程序 crash 好了」(我觉得这个态度挺好的,fail fast 是件好事[6]),所以专为 Cocoa 开发而推出的 Swift 没有 try/catch 也并不是很意外的事情。当然,我也不敢斩钉截铁地说未来版本里 try/catch 肯定不会出现,因为 Swift 毕竟和 Obj-C 共享运行时,如果 Swift 有朝一日也会要拿来写一些不得不处理底层抛上来的 NSException 的东西,那就必须能提供某种错误恢复机制,而不是简单地 crash。

(Swift 处理 NSError 的范式与 Objective-C 基本一致,而且有 optional 的助益,变得更简洁了。)
****************为什么有人说不提倡try….catch************************************************************
1.try catch 大部分时候是给程序调试用的!
2.
在你能保证你的代码足够好的前提下,能不用try catch就能避免的异常,绝对不要用try catch。
try - catch 是用来捕获异常的,比如项目中的数据库操作,文件读写操作等等。没必要对 try - catch 有任何不适。

当然,绝对不要乱使用 try - catch,不然你的项目总是抛异常,依靠异常来做所有的错误捕获操作是不好的习惯。比如,有一个界面需要用户输入数据,并且对用户输入的数据进行检查后保存进数据库,那么我们手工的做检查,比直接不做检查保存进数据库,依靠数据库的约束和主外键设置来对数据的合法性进行检查就要好很多。这样,就会在保存数据库之前排除掉很多可能导致错误的异常。太多的异常抛出不但会影响性能,而且也绝不是一个良好的编程习惯。

总结,try - catch 本身并不会很大地影响性能,应该说可以忽略它的存在。但是抛出很多异常就不是一个好现象,靠异常来检查所有的错误操作就绝对不好,它会影响性能,并导致不好的代码。
3.抛出的异常如果用try catch来处理的话,程序就会运行。这和我们现实是不符合的,我们有的程序发生的异常是由于使用者输入的错误引起的,就像输入a和b,求a/b的值这个程序,我们知道除数不能为0,所以抛出异常,如果用try catch来处理的话,则程序会自动解决这个问题,而我们想要的结果是假如输入0,系统应该报错,让我们重新输入数值,故用RuntimeException比较好
4.不是说try catch不好,当然使用try catch 机制 肯定增多你的代码执行压力,
多用于没有把握的代码,比如 数据库操作等,有把握的用try catch 机制 和画蛇添足 有什么区别,直接用if else解决不就好了

****************如何解决代码异常************************************************************
NSAssert

这个应该都比较熟悉,他的名字叫做“断言”。断言(assertion)是指在开发期间使用的、让程序在运行时进行自检的代码(通常是一个子程序或宏)。断言为真,则表明程序运行正常,而断言为假,则意味着它已经在代码中发现了意料之外的错误。断言对于大型的复杂程序或可靠性要求极高的程序来说尤其有用。而当断言为假的时候,几乎所有的系统的处理策略都是,让程序死掉,即Crash掉。方便你知道,程序出现了问题。

断言其实是“防御式编程”的常用的手段。防御式编程的主要思想是:子程序应该不因传入错误数据而被破坏,哪怕是由其他子程序产生的错误数据。这种思想是将可能出现的错误造成的影响控制在有限的范围内。断言能够有效的保证数据的正确性,防止因为脏数据让整个程序运行在不稳定的状态下面。

关于如何使用断言,还是参考《代码大全2》中“防御式编程”一章。这里简单的做了一点摘录,概括其大意:

  1. 用错误处理代码来处理预期会发生的状况,用断言来处理绝不应该发生的状况。
  2. 避免把需要执行的代码放到断言中
  3. 用断言来注解并验证前条件和后条件
  4. 对于高健壮性的代码,应该先使用断言再处理错误
  5. 对来源于内部系统的可靠的数据使用断言,而不要对外部不可靠的数据使用断言,对于外部不可靠数据,应该使用错误处理代码。
    而在IOS编程中,我们可以使用NSAssert来处理断言。比如:

    • (void)printMyName:(NSString *)myName
      {
      NSAssert(myName == nil, @”名字不能为空!”);
      NSLog(@”My name is %@.”,myName);
      }
      我们验证myName的安全性,需要保证其不能为空。NSAssert会检查其内部的表达式的值,如果为假则继续执行程序,如果不为假让程序Crash掉。

每一个线程都有它自己的断言捕获器(一个NSAssertionHanlder的实例),当断言发生时,捕获器会打印断言信息和当前的类名、方法名等信息。然后抛出一个NSInternalInconsistencyException异常让整个程序Crash掉。并且在当前线程的断言捕获器中执行handleFailureInMethod:object:file:lineNumber:description:以上述信息为输出。

当时,当程序发布的时候,不能把断言带入安装包,你不想让程序在用户机器上Crash掉吧。打开和关闭断言可以在项目设置中设置:

在release版本中设置了NS_BLOCK_ASSERTIONS之后断言失效。

尽可能不要用Try-Catch

并不是说Try-Catch这样的异常处理机制不好。而是,很多人在编程中,错误了使用了Try-Catch,把异常处理机制用在了核心逻辑中。把其当成了一个变种的GOTO使用。把大量的逻辑写在了Catch中。弱弱的说一句,这种情况干嘛不用ifelse呢。

而实际情况是,异常处理只是用户处理软件中出现异常的情况。常用的情况是子程序抛出错误,让上层调用者知道,子程序发生了错误,并让调用者使用合适的策略来处理异常。一般情况下,对于异常的处理策略就是Crash,让程序死掉,并且打印出堆栈信息。

而在IOS编程中,抛出错误的方式,往往采用更直接的方式。如果上层需要知道错误信息,一半会传入一个NSError的指针的指针:

  • (void) doSomething:(NSError* __autoreleasing*)error
    {

    if(error != NULL)
    {
    *error = [NSError new];
    }
    ….
    }
    而能够留给异常处理的场景就极少了,所以在IOS编程中尽量不要使用Try-Catch。

(PS:见到过使用Try-Catch来防止程序Crash的设计,如果不是迫不得已,尽量不要使用这种策略)

尽量将没有Crash掉的BUG,让它Crash掉

上面主要讲的是怎么知道Crash的“BUG”。对于合理的制造“BUG”还有一条就是尽量把没有Crash掉的“BUG”,让他Crash掉。这个没有比较靠谱的方法,靠暴力吧。比如写一些数组越界在里面之类的。比如那些难调的多线程BUG,想办法让他Crash掉吧,crash掉查找起来就比较方便了。

总之,就是抱着让程序“死掉”的心态去编程,向死而生。

****************代码异常总结************************************************************

1.苹果不鼓励使用try catch来处理代码异常,新开发的swift语言已经废弃了try catch语法。
2.代码异常尽可能使用NSError和NSAssert,开发原则上应该尽可能让程序crsh掉,不让出现不安全的代码,NSError许多原生类和方法自带NSError,不过过多介绍,NSAssert正好可以解决该问题,测试的时候尽可能让不安全的代码crash,发布的时候release版本可以把NSASSert隐藏掉。
http://www.cnblogs.com/xiaodao/archive/2012/07/04/2576292.html NSError使用
http://blog.csdn.net/univcore/article/details/16859263 NSAsssert使用
http://blog.jobbole.com/68678/ 代码异常分析以及处理办法

0 0
原创粉丝点击