Objective-C try/catch异常处理机制原理。

http://www.cnblogs.com/markhy/p/3169035.html

Objective-C使用@try @catch @finally来捕获并处理异常。处理异常需要用到NSException类,它是所有异常的基类。你可以直接使用NSException类来捕获异常,也可以继承一个新的类。

  Objective-C是C语言的扩充,它的异常处理机制是通过C标准库提供两个特殊的函数setjmp()和longjmp()函数实现的。如果对C的异常处理机制和setjmp、longjmp函数不了解的,建议先阅读:C语言异常处理机制

先来看看下面的例子:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
    @autoreleasepool
    {
        @try {
            NSException *e = [NSException
                              exceptionWithName:@"FileNotFoundException"
                              reason:@"File Not Found on System"
                              userInfo:nil];
            @throw e;
        }
        @catch (NSException *exception) {
            if ([[exception name] isEqualToString:NSInvalidArgumentException]) {
                NSLog(@"%@", exception);
            } else {
                @throw exception;
            }
        }
        @finally {
            NSLog(@"finally");
        }
    }
    return 0;
}

  例子很简单,在@try中抛出一个自定义的FileNotFoundException类型的异常,然后在@catch中判断捕获的异常是不是NSInvalidArgumentException类型,如果不是,将异常再次抛出。最后总是会执行@finally语句,一般异常处理的善后工作都放这里来做。

  如何才能了解它内部的工作流程,@try @catch @finally的定义无法查看。幸运的是我们可以通过Clang生成C的中间代码来了解try/catch原理。想了解Clang推荐阅读:编译器Clang介绍

  以上面的代码为例,使用文本编辑器将代码保存到main.m文件中,文件名可随便定义。打开终端输入:clang -rewrite-objc main.m 命令编译。

得到一份main.cpp文件:

struct objc_selector; struct objc_class;
struct __rw_objc_super { struct objc_object *object; struct objc_object *superClass; };
#ifndef _REWRITER_typedef_Protocol
typedef struct objc_object Protocol;
#define _REWRITER_typedef_Protocol
#endif
#define __OBJC_RW_DLLIMPORT extern
__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend(struct objc_object *, struct objc_selector *, ...);
__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper(struct objc_super *, struct objc_selector *, ...);
__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend_stret(struct objc_object *, struct objc_selector *, ...);
__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper_stret(struct objc_super *, struct objc_selector *, ...);
__OBJC_RW_DLLIMPORT double objc_msgSend_fpret(struct objc_object *, struct objc_selector *, ...);
__OBJC_RW_DLLIMPORT struct objc_object *objc_getClass(const char *);
__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass(struct objc_class *);
__OBJC_RW_DLLIMPORT struct objc_object *objc_getMetaClass(const char *);
__OBJC_RW_DLLIMPORT void objc_exception_throw(struct objc_object *);
__OBJC_RW_DLLIMPORT void objc_exception_try_enter(void *);
__OBJC_RW_DLLIMPORT void objc_exception_try_exit(void *);
__OBJC_RW_DLLIMPORT struct objc_object *objc_exception_extract(void *);
__OBJC_RW_DLLIMPORT int objc_exception_match(struct objc_class *, struct objc_object *);
__OBJC_RW_DLLIMPORT void objc_sync_enter(struct objc_object *);
__OBJC_RW_DLLIMPORT void objc_sync_exit(struct objc_object *);
__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);
#ifndef __FASTENUMERATIONSTATE
struct __objcFastEnumerationState {
    unsigned long state;
    void **itemsPtr;
    unsigned long *mutationsPtr;
    unsigned long extra[5];
};
__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);
#define __FASTENUMERATIONSTATE
#endif
#ifndef __NSCONSTANTSTRINGIMPL
struct __NSConstantStringImpl {
  int *isa;
  int flags;
  char *str;
  long length;
};
#ifdef CF_EXPORT_CONSTANT_STRING
extern "C" __declspec(dllexport) int __CFConstantStringClassReference[];
#else
__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];
#endif
#define __NSCONSTANTSTRINGIMPL
#endif
#ifndef BLOCK_IMPL
#define BLOCK_IMPL
struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};
// Runtime copy/destroy helper functions (from Block_private.h)
#ifdef __OBJC_EXPORT_BLOCKS
extern "C" __declspec(dllexport) void _Block_object_assign(void *, const void *, const int);
extern "C" __declspec(dllexport) void _Block_object_dispose(const void *, const int);
extern "C" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];
extern "C" __declspec(dllexport) void *_NSConcreteStackBlock[32];
#else
__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);
__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);
__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];
__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];
#endif
#endif
#define __block
#define __weak

#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)
static __NSConstantStringImpl __NSConstantStringImpl_main_m_0 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"FileNotFoundException",21};
static __NSConstantStringImpl __NSConstantStringImpl_main_m_1 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"File Not Found on System",24};
static __NSConstantStringImpl __NSConstantStringImpl_main_m_2 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"%@",2};
static __NSConstantStringImpl __NSConstantStringImpl_main_m_3 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"finally",7};
//
//  main.c
//  TestBlock
//
//  Created by xxxx on 13-6-2.
//  Copyright (c) 2013 xxxx. All rights reserved.
//

#include <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
    @autoreleasepool
    {
        /* @try scope begin */
        {
            struct _objc_exception_data
            {
                int buf[18/*32-bit i386*/];
                char *pointers[4];
            } _stack;

            id volatile _rethrow = 0;
            objc_exception_try_enter(&_stack);

            if (!_setjmp(_stack.buf)) /* @try block continue */
            {
                NSException *e = ((NSException *(*)(id, SEL, NSString *, NSString *, NSDictionary *))(void *)objc_msgSend)(objc_getClass("NSException"), sel_registerName("exceptionWithName:reason:userInfo:"), (NSString *)&__NSConstantStringImpl_main_m_0, (NSString *)&__NSConstantStringImpl_main_m_1, (NSDictionary *)((void *)0));

                objc_exception_throw(e);

            } /* @catch begin */ else {

                id _caught = objc_exception_extract(&_stack);
                objc_exception_try_enter (&_stack);

                if (_setjmp(_stack.buf))
                    _rethrow = objc_exception_extract(&_stack);

                else { /* @catch continue */
                    if (objc_exception_match((struct objc_class *)objc_getClass("NSException"), (struct objc_object *)_caught)) {
                        NSException *exception = _caught;

                        if (((BOOL (*)(id, SEL, NSString *))(void *)objc_msgSend)((id)((NSString *(*)(id, SEL))(void *)objc_msgSend)((id)exception, sel_registerName("name")), sel_registerName("isEqualToString:"), (NSString *)NSInvalidArgumentException)) {

                            NSLog((NSString *)&__NSConstantStringImpl_main_m_2, exception);
                        } else {

                            objc_exception_throw( exception);
                        }

                    } /* last catch end */ else {
                        _rethrow = _caught;
                        objc_exception_try_exit(&_stack);
                    }
                } /* @catch end */
            }
            /* @finally */
            {
                if (!_rethrow) objc_exception_try_exit(&_stack);

                NSLog((NSString *)&__NSConstantStringImpl_main_m_3);

                if (_rethrow) objc_exception_throw(_rethrow);
            }

        } /* @try scope end */

    }
    return 0;
}

文件中信息量太大,咱们只看main函数部分,下面的代码把main函数的代码作了注释说明:

#include <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
    @autoreleasepool
    {
        /**
         * try/catch的作用域从这里开始
         */
        /* @try scope begin */
        {
            /**
             * 首先定义一个_objc_exception_data类型的结构体,用来保存异常现场的数据。
             */
            struct _objc_exception_data
            {
                /**
                 * buf变量就是c语言中的jmp_buf
                 * jmp_buf的定义可在setjmp.h文件中找到:
                 *
                 *      #define _JBLEN        (10 + 16 + 2)
                 *      #define _JBLEN_MAX    _JBLEN
                 *
                 *      typedef int jmp_buf[_JBLEN];
                 */
                int buf[18/*32-bit i386*/];

                /**
                 * pointers[0]用来存储通过@throw抛出的异常对象,
                 * pointers[1]存储下一个_stack数据。
                 */
                char *pointers[4];
            } _stack;

            /**
             * _rethrow保存可能在@catch中再次抛出的异常对象。
             */
            id volatile _rethrow = 0;

            /**
             * 因为异常处理支持嵌套,_stack会被存储在一个全局的栈中,这个栈用单链表的存储结构表示。
             * objc_exception_try_enter函数将_stack压栈。
             */
            objc_exception_try_enter(&_stack);

            /**
             * _setjmp是C的函数,用于保存当前程序现场。
             * _setjmp需要传入一个jmp_buf参数,保存当前需要用到的寄存器的值。
             * _setjmp()它能返回两次,第一次是初始化时,返回0,第二次遇到_longjmp()函数调用会返回,返回值由_longjmp的第二个参数决定。
             * 如果对_setjmp()和_longjmp()概念不太了解的,请参考C语言的异常处理机制。
             *
             * 下面_setjmp()初始化返回0,然后执行if{}中也就是@try{}中的代码。
             */
            if (!_setjmp(_stack.buf)) /* @try block continue */
            {
                /**
                 * 创建一个NSException对象,对应代码:
                 *
                 *             NSException *e = [NSException
                 *                               exceptionWithName:@"FileNotFoundException"
                 *                               reason:@"File Not Found on System"
                 *                               userInfo:nil];
                 */
                NSException *e = ((NSException *(*)(id, SEL, NSString *, NSString *, NSDictionary *))(void *)objc_msgSend)(objc_getClass("NSException"), sel_registerName("exceptionWithName:reason:userInfo:"), (NSString *)&__NSConstantStringImpl_main_m_0, (NSString *)&__NSConstantStringImpl_main_m_1, (NSDictionary *)((void *)0));

                /**
                 * 抛出异常对象,对应代码:@throw e;
                 *
                 * objc_exception_throw函数实现步骤如下:
                 * 1. 把e对象保存到_stack->pointers[0]中使其在@catch{}中能被捕获。
                 * 2. 将_stack从全局栈中弹出。
                 * 3. 调用_longjmp()跳转到前面if语句中的_setjmp()位置。_longjmp()使得_setjmp()函数第二次返回,
                 * 返回值为1,所以会执行else{}中也就是@catch{}中的代码。
                 */
                objc_exception_throw(e);

            } /* @catch begin */ else {

                /**
                 * objc_exception_extract函数从_stack->pointers[0]中取得上面抛出的异常对象。
                 */
                id _caught = objc_exception_extract(&_stack);

                /**
                 * 这里为何再次调用objc_exception_try_enter对_stack压栈?先保留这个疑问,继续看下面的代码。
                 */
                objc_exception_try_enter (&_stack);

                /**
                 * 在@catch中设置一个跳转位置
                 */
                if (_setjmp(_stack.buf))

                    /**
                     * 如果@catch{}中再次抛出异常,在这里捕获。
                     */
                    _rethrow = objc_exception_extract(&_stack);

                else { /* @catch continue */

                    /**
                     * objc_exception_match函数判断_caught对象是否是需要捕获的目标对象。对应代码:
                     *
                     * @catch (NSException *exception) {
                     */
                    if (objc_exception_match((struct objc_class *)objc_getClass("NSException"), (struct objc_object *)_caught)) {
                        NSException *exception = _caught;

                        /**
                         * 比较捕获的异常是不是NSInvalidArgumentException类型。对应代码:
                         *
                         * if ([[exception name] isEqualToString:NSInvalidArgumentException]) {
                         *      NSLog(@"%@", exception);
                         *
                         */
                        if (((BOOL (*)(id, SEL, NSString *))(void *)objc_msgSend)((id)((NSString *(*)(id, SEL))(void *)objc_msgSend)((id)exception, sel_registerName("name")), sel_registerName("isEqualToString:"), (NSString *)NSInvalidArgumentException)) {

                            NSLog((NSString *)&__NSConstantStringImpl_main_m_2, exception);
                        } else {

                            /**
                             * 抛出异常对象,然后跳转到前面@catch中的if语句中的_setjmp()位置。
                             * 这就解释了前面为什么要在@catch中再次将_stack压栈和调用_setjmp()的原因。
                             * 在当前@catch中,如果不设置一个跳转点来捕获@catch中抛出的异常,那么程序就直接跳转到全局栈的下一个@catch中,而下面的@finally{}代码就无法执行。
                             * 在@catch中设置跳转点就是为了最后总能执行@finally中的代码。
                             */
                            objc_exception_throw( exception);
                        }

                    } /* last catch end */ else {

                        /**
                         * 如果异常对象没被处理,先将其保存到_rethrow变量。
                         * objc_exception_try_exit函数将_stack从全局栈中弹出。
                         */
                        _rethrow = _caught;
                        objc_exception_try_exit(&_stack);
                    }
                } /* @catch end */
            }
            /* @finally */
            {
                if (!_rethrow) objc_exception_try_exit(&_stack);

                NSLog((NSString *)&__NSConstantStringImpl_main_m_3);

                /**
                 * _rethrow是前面@catch中没有被处理的或被捕获的异常对象,
                 * 最后,_rethrow异常对象被抛到全局栈的下一个@catch中。
                 */
                if (_rethrow) objc_exception_throw(_rethrow);
            }

        } /* @try scope end */

    }
    return 0;
}

  以上代码中还涉及了objc_exception_try_enter、objc_exception_extract、objc_exception_throw、objc_exception_try_exit等函数,这些函数可以在苹果开源的objc4的objc-exception.mm文件中找到,objc4源码可在这里下载。下面代码只显示部分方便阅读:

typedef struct {
    int version;
    void (*throw_exc)(id);        // version 0
    void (*try_enter)(void *);    // version 0
    void (*try_exit)(void *);    // version 0
    id     (*extract)(void *);    // version 0
    int    (*match)(Class, id);    // version 0
} objc_exception_functions_t;

static objc_exception_functions_t xtab;

// forward declaration
static void set_default_handlers();

/*
 * Exported functions
 */

// get table; version tells how many
void objc_exception_get_functions(objc_exception_functions_t *table) {
    // only version 0 supported at this point
    if (table && table->version == 0)
        *table = xtab;
}

// set table
void objc_exception_set_functions(objc_exception_functions_t *table) {
    // only version 0 supported at this point
    if (table && table->version == 0)
        xtab = *table;
}

/*
 * The following functions are
 * synthesized by the compiler upon encountering language constructs
 */

void objc_exception_throw(id exception) {
    if (!xtab.throw_exc) {
        set_default_handlers();
    }

    if (PrintExceptionThrow) {
        _objc_inform("EXCEPTIONS: throwing %p (%s)",
                     exception, object_getClassName(exception));
        void* callstack[500];
        int frameCount = backtrace(callstack, 500);
        backtrace_symbols_fd(callstack, frameCount, fileno(stderr));
    }

    OBJC_RUNTIME_OBJC_EXCEPTION_THROW(exception);  // dtrace probe to log throw activity.
    xtab.throw_exc(exception);
    _objc_fatal("objc_exception_throw failed");
}

void objc_exception_try_enter(void *localExceptionData) {
    if (!xtab.throw_exc) {
        set_default_handlers();
    }
    xtab.try_enter(localExceptionData);
}

void objc_exception_try_exit(void *localExceptionData) {
    if (!xtab.throw_exc) {
        set_default_handlers();
    }
    xtab.try_exit(localExceptionData);
}

id objc_exception_extract(void *localExceptionData) {
    if (!xtab.throw_exc) {
        set_default_handlers();
    }
    return xtab.extract(localExceptionData);
}

int objc_exception_match(Class exceptionClass, id exception) {
    if (!xtab.throw_exc) {
        set_default_handlers();
    }
    return xtab.match(exceptionClass, exception);
}

// quick and dirty exception handling code
// default implementation - mostly a toy for use outside/before Foundation
// provides its implementation
// Perhaps the default implementation should just complain loudly and quit

extern void _objc_inform(const char *fmt, ...);

typedef struct { jmp_buf buf; void *pointers[4]; } LocalData_t;

typedef struct _threadChain {
    LocalData_t *topHandler;
    objc_thread_t perThreadID;
    struct _threadChain *next;
}
    ThreadChainLink_t;

static ThreadChainLink_t ThreadChainLink;

static ThreadChainLink_t *getChainLink() {
    // follow links until thread_self() found (someday) XXX
    objc_thread_t self = thread_self();
    ThreadChainLink_t *walker = &ThreadChainLink;
    while (walker->perThreadID != self) {
        if (walker->next != NULL) {
            walker = walker->next;
            continue;
        }
        // create a new one
        // XXX not thread safe (!)
        // XXX Also, we don‘t register to deallocate on thread death
        walker->next = (ThreadChainLink_t *)malloc(sizeof(ThreadChainLink_t));
        walker = walker->next;
        walker->next = NULL;
        walker->topHandler = NULL;
        walker->perThreadID = self;
    }
    return walker;
}

static void default_try_enter(void *localExceptionData) {
    LocalData_t *data = (LocalData_t *)localExceptionData;
    ThreadChainLink_t *chainLink = getChainLink();
    data->pointers[1] = chainLink->topHandler;
    chainLink->topHandler = data;
    if (PrintExceptions) _objc_inform("EXCEPTIONS: entered try block %p\n", chainLink->topHandler);
}

static void default_throw(id value) {
    ThreadChainLink_t *chainLink = getChainLink();
    LocalData_t *led;
    if (value == nil) {
        if (PrintExceptions) _objc_inform("EXCEPTIONS: objc_exception_throw with nil value\n");
        return;
    }
    if (chainLink == NULL) {
        if (PrintExceptions) _objc_inform("EXCEPTIONS: No handler in place!\n");
        return;
    }
    if (PrintExceptions) _objc_inform("EXCEPTIONS: exception thrown, going to handler block %p\n", chainLink->topHandler);
    led = chainLink->topHandler;
    chainLink->topHandler = (LocalData_t *)
        led->pointers[1];    // pop top handler
    led->pointers[0] = value;            // store exception that is thrown
#if TARGET_OS_WIN32
    longjmp(led->buf, 1);
#else
    _longjmp(led->buf, 1);
#endif
}

static void default_try_exit(void *led) {
    ThreadChainLink_t *chainLink = getChainLink();
    if (!chainLink || led != chainLink->topHandler) {
        if (PrintExceptions) _objc_inform("EXCEPTIONS: *** mismatched try block exit handlers\n");
        return;
    }
    if (PrintExceptions) _objc_inform("EXCEPTIONS: removing try block handler %p\n", chainLink->topHandler);
    chainLink->topHandler = (LocalData_t *)
        chainLink->topHandler->pointers[1];    // pop top handler
}

static id default_extract(void *localExceptionData) {
    LocalData_t *led = (LocalData_t *)localExceptionData;
    return (id)led->pointers[0];
}

static int default_match(Class exceptionClass, id exception) {
    //return [exception isKindOfClass:exceptionClass];
    Class cls;
    for (cls = _object_getClass(exception); nil != cls; cls = _class_getSuperclass(cls))
        if (cls == exceptionClass) return 1;
    return 0;
}

static void set_default_handlers() {
    objc_exception_functions_t default_functions = {
        0, default_throw, default_try_enter, default_try_exit, default_extract, default_match };

    // should this always print?
    if (PrintExceptions) _objc_inform("EXCEPTIONS: *** Setting default (non-Foundation) exception mechanism\n");
    objc_exception_set_functions(&default_functions);
}

void exception_init(void)
{
    // nothing to do
}

void _destroyAltHandlerList(struct alt_handler_list *list)
{
    // nothing to do
}

// !__OBJC2__
#else
// __OBJC2__

时间: 2024-08-05 07:09:35

Objective-C try/catch异常处理机制原理。的相关文章

ASP.NET(C#)中的try catch异常处理机制

在开发一个Umbraco平台系统的过程中,遇到了问题. 写的代码如下 fileUrl = MediaHelper.GetMediaUrl(Convert.ToInt32(publishedContent.GetProperty("mediaPdf").DataValue.ToString())); 这个是在Umbraco后台建立了一个pdfInfo的DocumentType, 它里面有个属性是mediaPicker, 从media文件夹中选取pdf文件.这个属性名称是mediaPdf,

java——关于异常处理机制的简单原理和应用

异常处理机制的简单原理和应用 一.Execption可以分为java标准定义的异常和程序员自定义异常2种 (1)一种是当程序违反了java语规则的时候,JAVA虚拟机就会将发生的错误表示为一个异常.这里语法规则指的是JAVA类库内置的语义检查. 例如 int i = 2 / 0 或者 String str = null;str.length(); (2)另一种情况就是JAVA允许程序员扩展这种语义检查,程序员可以创建自己的异常,并自由选择在何时用throw关键字引发异常. 例如 Exceptio

Java中的异常处理机制的简单原理和应用。

异常是指java程序运行时(非编译)所发生的非正常情况或错误,与现实生活中的事件很相似,现实生活中的事件可以包含事件发生的时间.地点.人物.情节等信息,可以用一个对象来表示,Java使用面向对象的方式来处理异常,它把程序中发生的每个异常也都分别封装到一个对象来表示的,该对象中包含有异常的信息. Java对异常进行了分类,不同类型的异常分别用不同的Java类表示,所有异常的根类为java.lang.Throwable,Throwable下面又派生了两个子类:Error和Exception,Erro

Java异常处理机制:try...catch...的执行流程

Java异常处理机制:try...catch...的执行流程 在项目中遇到try...catch...语句,因为对Java异常处理机制的流程不是很清楚,导致对相关逻辑代码不理解.所以现在来总结Java异常处理机制的处理流程: 1.异常处理的机制如下: 在方法中用 try... catch... 语句捕获并处理异常,catch 语句可以有多个,用来匹配多个不同类型的异常. 对于处理不了的异常或者要转型的异常,在方法的声明处通过 throws 声明异常,通过throw语句拋出异常,即由上层的调用方法

Java从零开始(3)异常处理机制

异常处理是程序设计中一个非常重要的方面,也是程序设计的一大难点,从C开始,你也许已经知道如何用if...else...来控制异常了,也许是自发的,然而这种控制异常痛苦,同一个异常或者错误如果多个地方出现,那么你每个地方都要做相同处理,感觉相当的麻烦! Java语言在设计的当初就考虑到这些问题,提出异常处理的框架的方案,所有的异常都可以用一个类型来表示,不同类型的异常对应不同的子类异常(这里的异常包括错误概念),定义异常处理的规范,在1.4版本以后增加了异常链机制,从而便于跟踪异常!这是Java语

(十)struts2的异常处理机制

成熟的MVC框架应该提供成熟的异常处理机制.当然可以在方法中手动捕捉异常,当捕捉到特定异常时,返回特定逻辑视图名. 这种方式非常繁琐,需要在方法中写大量try catch块,最大的缺点还是一旦需要改变异常处理方法时,需要修改代码. 最好的方式是通过声明式的方式管理异常处理.struts2提供了一种声明式的异常处理方式. 一.原理 我们看Action接口中的execute方法声明. public String execute() throws Exception 这就意味着我们重写该方法时,无需进

深入理解Java异常处理机制

1. 引子 try-catch-finally恐怕是大家再熟悉不过的语句了,而且感觉用起来也是很简单,逻辑上似乎也是很容易理解.不过,我亲自体验的"教训"告诉我,这个东西可不是想象中的那么简单.听话.不信?那你看看下面的代码,"猜猜"它执行后的结果会是什么?不要往后看答案.也不许执行代码看真正答案哦.如果你的答案是正确,那么这篇文章你就不用浪费时间看啦. <span style="background-color: rgb(255, 255, 255

Java异常处理机制的秘密

一.结论 这些结论你可能从未听说过,但其正确性是毋庸置疑的,不妨先看看: 1.catch中throw不一定能抛回到上一层,因为finally中的return会抑制这个throw2.finally中throw一定能抛回上一层,因为此时其后的return不会被执行到(throw中断了正常的顺序流)3.在try/catch中return并不会直接返回上一层,而是先执行finally再返回 二.一段小程序 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

C++学习笔记27:异常处理机制

一.异常处理机制基础 异常的定义 程序中可以检测的运行不正常的情况 异常处理的基本流程 某段程序代码在执行操作时发生特殊情况,引发一个特定的异常 另一段程序代码捕获该异常并处理它 二.异常的引发 throw 三.异常的捕获 try { ... } catch(...) 四.异常类与异常对象 五.异常处理策略 异常类可以派生和继承,形成类库架构 可捕获的异常对象的型式 普通型式(包括类):异常对象需要拷贝 对某型式对象的引用:没有额外的拷贝动作 指向某型式对象的指针:要求对象动态构造或者在catc