精华内容
下载资源
问答
  • 在c++中,可以直接抛出异常之后自己进行捕捉处理,如:(这样就可以在任何自己得到不想要的结果的时候进行中断,比如在进行数据库事务操作的时候,如果某一个语句返回...int main () {try{throw 1;throw "error";}c...

    在c++中,可以直接抛出异常之后自己进行捕捉处理,如:(这样就可以在任何自己得到不想要的结果的时候进行中断,比如在进行数据库事务操作的时候,如果某一个语句返回SQL_ERROR则直接抛出异常,在catch块中进行事务回滚(回滚怎么理解?))。

    #include

    #include

    using namespace std;

    int main () {

    try

    {

    throw 1;

    throw "error";

    }

    catch(char *str)

    {

    cout << str << endl;

    }

    catch(int i)

    {

    cout << i << endl;

    }

    }

    也可以自己定义异常类来进行处理:

    #include

    #include

    using namespace std;

    //可以自己定义Exception

    class myexception: public exception

    {

    virtual const char* what() const throw()

    {

    return "My exception happened";

    }

    }myex;

    int main () {

    try

    {

    if(true) //如果,则抛出异常;

    throw myex;

    }

    catch (exception& e)

    {

    cout << e.what() << endl;

    }

    return 0;

    }

    同时也可以使用标准异常类进行处理:

    #include

    #include

    using namespace std;

    int main () {

    try

    {

    int* myarray= new int[100000];

    }

    catch (exception& e)

    {

    cout << "Standard exception: " << e.what() << endl;

    }

    return 0;

    }

    一、简单的例子

    首先通过一个简单的例子来熟悉C++ 的 try/catch/throw(可根据单步调试来熟悉,try catch throw部分是如何运行的):

    #include

    #include "iostream"

    using namespace std;

    double fuc(double x, double y) //定义函数

    {

    if(y==0)

    {

    throw y; //除数为0,抛出异常

    }

    return x/y; //否则返回两个数的商

    }

    int _tmain(int argc, _TCHAR* argv[])

    {

    double res;

    try //定义异常

    {

    res=fuc(2,3);

    cout<

    res=fuc(4,0); //出现异常

    }

    catch(double) //捕获并处理异常

    {

    cerr<

    exit(1); //异常退出程序

    }

    return 0;

    }

    catch 的数据类型需要与throw出来的数据类型相匹配的。

    二、catch(...)的作用

    catch(…)能够捕获多种数据类型的异常对象,所以它提供给程序员一种对异常对象更好的控制手段,使开发的软件系统有很好的可靠性。因此一个比较有经验的程序员通常会这样组织编写它的代码模块,如下:

    void Func()

    {

    try

    {

    // 这里的程序代码完成真正复杂的计算工作,这些代码在执行过程中

    // 有可能抛出DataType1、DataType2和DataType3类型的异常对象。

    }

    catch(DataType1& d1)

    {

    }

    catch(DataType2& d2)

    {

    }

    catch(DataType3& d3)

    {

    }

    /*********************************************************  注意上面try block中可能抛出的DataType1、DataType2和DataType3三

    种类型的异常对象在前面都已经有对应的catch block来处理。但为什么

    还要在最后再定义一个catch(…) block呢?这就是为了有更好的安全性和

    可靠性,避免上面的try block抛出了其它未考虑到的异常对象时导致的程

    序出现意外崩溃的严重后果,而且这在用VC开发的系统上更特别有效,因

    为catch(…)能捕获系统出现的异常,而系统异常往往令程序员头痛了,现

    在系统一般都比较复杂,而且由很多人共同开发,一不小心就会导致一个

    指针变量指向了其它非法区域,结果意外灾难不幸发生了。catch(…)为这种

    潜在的隐患提供了一种有效的补救措施。  *********************************************************/

    catch(…)

    {

    }

    }

    三、异常中采用面向对象的处理

    首先看下面的例子:

    void OpenFile(string f)

    {

    try

    {

    // 打开文件的操作,可能抛出FileOpenException

    }

    catch(FileOpenException& fe)

    {

    // 处理这个异常,如果这个异常可以很好的得以恢复,那么处理完毕后函数

    // 正常返回;否则必须重新抛出这个异常,以供上层的调用函数来能再次处

    // 理这个异常对象

    int result = ReOpenFile(f);

    if (result == false) throw;

    }

    }

    void ReadFile(File f)

    {

    try

    {

    // 从文件中读数据,可能抛出FileReadException

    }

    catch(FileReadException& fe)

    {

    // 处理这个异常,如果这个异常可以很好的得以恢复,那么处理完毕后函数

    // 正常返回;否则必须重新抛出这个异常,以供上层的调用函数来能再次处

    // 理这个异常对象

    int result = ReReadFile(f);

    if (result == false) throw;

    }

    }

    void WriteFile(File f)

    {

    try

    {

    // 往文件中写数据,可能抛出FileWriteException

    }

    catch(FileWriteException& fe)

    {

    // 处理这个异常,如果这个异常可以很好的得以恢复,那么处理完毕后函数

    // 正常返回;否则必须重新抛出这个异常,以供上层的调用函数来能再次处理这个异常对象

    int result = ReWriteFile(f);

    if (result == false) throw;

    }

    }

    void Func()

    {

    try

    {

    // 对文件进行操作,可能出现FileWriteException、FileWriteException

    // 和FileWriteException异常

    OpenFile(…);

    ReadFile(…);

    WriteFile(…);

    }

    // 注意:FileException是FileOpenException、FileReadException和FileWriteException

    // 的基类,因此这里定义的catch(FileException& fe)能捕获所有与文件操作失败的异

    // 常。

    catch(FileException& fe)

    {

    ExceptionInfo* ef = fe.GetExceptionInfo();

    cout << “操作文件时出现了不可恢复的错误,原因是:”<< fe << endl;

    }

    }

    下面是更多面向对象和异常处理结合的例子:

    #include

    class ExceptionClass

    {

    char* name;

    public:

    ExceptionClass(const char* name="default name")

    {

    cout<

    this->name=name;

    }

    ~ExceptionClass()

    {

    cout<

    }

    void mythrow()

    {

    throw ExceptionClass("my throw");

    }

    }

    void main()

    {

    ExceptionClass e("Test");

    try

    {

    e.mythrow();

    }

    catch(...)

    {

    cout<

    }

    }

    这是输出信息:

    Construct Test

    Construct my throw

    Destruct my throw

    ****************

    Destruct my throw (这里是异常处理空间中对异常类的拷贝的析构)

    Destruct Test

    ======================================

    不过一般来说我们可能更习惯于把会产生异常的语句和要throw的异常类分成不同的类来写,下面的代码可以是我们更愿意书写的:

    class ExceptionClass

    {

    public:

    ExceptionClass(const char* name="Exception Default Class")

    {

    cout<

    }

    ~ExceptionClass()

    {

    cout<

    }

    void ReportError()

    {

    cout<

    }

    };

    class ArguClass

    {

    char* name;

    public:

    ArguClass(char* name="default name")

    {

    cout<

    this->name=name;

    }

    ~ArguClass()

    {

    cout<

    }

    void mythrow()

    {

    throw ExceptionClass("my throw");

    }

    };

    _tmain()

    {

    ArguClass e("haha");

    try

    {

    e.mythrow();

    }

    catch(int)

    {

    cout<

    }

    catch(ExceptionClass pTest)

    {

    pTest.ReportError();

    }

    catch(...)

    {

    cout<

    }

    }

    输出Message:

    Construct String::haha

    Exception Class Construct String

    Exception Class Destruct String

    Exception Class:: This is Report Error Message

    Exception Class Destruct String

    Destruct String::haha

    四、构造和析构中的异常抛出

    先看个程序,假如我在构造函数的地方抛出异常,这个类的析构会被调用吗?可如果不调用,那类里的东西岂不是不能被释放了?

    #include

    #include

    class ExceptionClass1

    {

    char* s;

    public:

    ExceptionClass1()

    {

    cout<

    s=new char[4];

    cout<

    throw 18;

    }

    ~ExceptionClass1()

    {

    cout<

    delete[] s;

    }

    };

    void main()

    {

    try

    {

    ExceptionClass1 e;

    }

    catch(...)

    {}

    }

    结果为:

    ExceptionClass1()

    throw a exception

    在这两句输出之间,我们已经给S分配了内存,但内存没有被释放(因为它是在析构函数中释放的)。应该说这符合实际现象,因为对象没有完整构造。

    为了避免这种情况,我想你也许会说:应避免对象通过本身的构造函数涉及到异常抛出。即:既不在构造函数中出现异常抛出,也不应在构造函数调用的一切东西中出现异常抛出。

    但是在C++中可以在构造函数中抛出异常,经典的解决方案是使用STL的标准类auto_ptr。

    那么,在析构函数中的情况呢?我们已经知道,异常抛出之后,就要调用本身的析构函数,如果这析构函数中还有异常抛出的话,则已存在的异常尚未被捕获,会导致异常捕捉不到。

    五、标准C++异常类

    标准异常都派生自一个公共的基类exception。基类包含必要的多态性函数提供异常描述,可以被重载。下面是exception类的原型:

    class exception

    {

    public:

    exception() throw();

    exception(const exception& rhs) throw();

    exception& operator=(const exception& rhs) throw();

    virtual ~exception() throw();

    virtual const char *what() const throw();

    };

    C++有很多的标准异常类:

    namespace std

    {

    //exception派生

    class logic_error; //逻辑错误,在程序运行前可以检测出来

    //logic_error派生

    class domain_error; //违反了前置条件

    class invalid_argument; //指出函数的一个无效参数

    class length_error; //指出有一个超过类型size_t的最大可表现值长度的对象的企图

    class out_of_range; //参数越界

    class bad_cast; //在运行时类型识别中有一个无效的dynamic_cast表达式

    class bad_typeid; //报告在表达试typeid(*p)中有一个空指针p

    //exception派生

    class runtime_error; //运行时错误,仅在程序运行中检测到

    //runtime_error派生

    class range_error; //违反后置条件

    class overflow_error; //报告一个算术溢出

    class bad_alloc; //存储分配错误

    }

    标准库异常类定义在以下四个头文件中

    1、exception头文件:定义了最常见的标准异常类,其类名为exception。只通知异常的产生,但不会提供更多的信息

    2、stdexcept头文件定义了以下几种常见异常类

    函数   功能或作用

    exception 最常见的问题

    runtime_error 运行时错误:仅在运行时才能检测到的问题

    range_error 运行时错误:生成的结果超出了有意义的值域范围

    overflow_error 运行时错误:计算上溢

    underflow_error 运行时错误:计算下溢

    logic_error 逻辑错误:可在运行前检测到的问题

    domain_error 逻辑错误:参数的结果值不存在

    invalid_argument 逻辑错误:不合适的参数

    length_error 逻辑错误:试图生成一个超出该类型最大长度的对象

    out_of_range 逻辑错误:使用一个超出有效范围的值

    3、new头文件定义了bad_alloc异常类型,提供因无法分配内存而由new抛出的异常

    4、type_info头文件定义了bad_cast异常类型(要使用type_info必须包含typeinfo头文件)

    下面是使用异常类的例子:

    首先,我定义了几个异常类,这些类也可以从标准异常类进行派生,如下

    class BadInitializers

    {

    public:

    BadInitializers() {}

    };

    class OutOfBounds

    {

    public:

    OutOfBounds(int i) { cout<

    };

    class SizeMismatch

    {

    public:

    SizeMismatch() {}

    };

    然后要在程序中需要的地方使用throw来抛出异常类,两个抛出异常类的例子如下

    template

    Array1D::Array1D(int sz)

    {

    if(sz<0)

    {

    //throw BadInitializers();

    throw invalid_argument("Size has to be bigger than 0!!!");

    }

    size=sz;

    element=new T[size];

    }

    template

    T &Array1D::operator[](int i) const

    {

    if(i<0||i>=size)

    {

    throw OutOfBounds(i);

    }

    return element[i];

    }

    然后在主程序中使用try...catch...来捕获异常,并进行相应的处理,如下

    try

    {

    int i=0;

    Array1D a1(5);

    a1[0]=1;

    a1[1]=3;

    a1[2]=5;

    a1[3]=7;

    a1[4]=8;

    Array1D a2(a1);

    for(i=0;i

    {

    cout<

    }

    cout<

    Array1D a3(5);

    a3=a1+a2;

    cout<

    }

    catch(BadInitializers)

    {

    cout<

    }

    catch(OutOfBounds &e)

    {

    cout<

    }

    catch(SizeMismatch &e)

    {

    cout<

    }

    catch(invalid_argument &e)

    {

    cout<

    }

    catch(...)

    {

    cout<

    }

    六、try finally使用

    __try

    {

    file://保护块

    }

    __finally

    {

    file://结束处理程序

    }

    在上面的代码段中,操作系统和编译程序共同来确保结束处理程序中的__f i n a l l y代码块能够被执行,不管保护体(t r y块)是如何退出的。不论你在保护体中使用r e t u r n,还是g o t o,或者是longjump,结束处理程序(f i n a l l y块)都将被调用。

    我们来看一个实列:(返回值:10, 没有Leak,性能消耗:小)

    DWORD Func_SEHTerminateHandle()

    {

    DWORD dwReturnData = 0;

    HANDLE hSem = NULL;

    const char* lpSemName = "TermSem";

    hSem = CreateSemaphore(NULL, 1, 1, lpSemName);

    __try

    {

    WaitForSingleObject(hSem,INFINITE);

    dwReturnData = 5;

    }

    __finally

    {

    ReleaseSemaphore(hSem,1,NULL);

    CloseHandle(hSem);

    }

    dwReturnData += 5;

    return dwReturnData;

    }

    这段代码应该只是做为一个基础函数,我们将在后面修改它,来看看结束处理程序的作用:

    ====================

    在代码加一句:(返回值:5, 没有Leak,性能消耗:中下)

    DWORD Func_SEHTerminateHandle()

    {

    DWORD dwReturnData = 0;

    HANDLE hSem = NULL;

    const char* lpSemName = "TermSem";

    hSem = CreateSemaphore(NULL, 1, 1, lpSemName);

    __try

    {

    WaitForSingleObject(hSem,INFINITE);

    dwReturnData = 5;

    return dwReturnData;

    }

    __finally

    {

    ReleaseSemaphore(hSem,1,NULL);

    CloseHandle(hSem);

    }

    dwReturnData += 5;

    return dwReturnData;

    }

    在try块的末尾增加了一个return语句。这个return语句告诉编译程序在这里要退出这个函数并返回dwTemp变量的内容,现在这个变量的值是5。但是,如果这个return语句被执行,该线程将不会释放信标,其他线程也就不能再获得对信标的控制。可以想象,这样的执行次序会产生很大的问题,那些等待信标的线程可能永远不会恢复执行。

    通过使用结束处理程序,可以避免return语句的过早执行。当return语句试图退出try块时,编译程序要确保finally块中的代码首先被执行。要保证finally块中的代码在try块中的return语句退出之前执行。在程序中,将ReleaseSemaphore的调用放在结束处理程序块中,保证信标总会被释放。这样就不会造成一个线程一直占有信标,否则将意味着所有其他等待信标的线程永远不会被分配CPU时间。

    在finally块中的代码执行之后,函数实际上就返回。任何出现在finally块之下的代码将不再执行,因为函数已在try块中返回。所以这个函数的返回值是5,而不是10。

    读者可能要问编译程序是如何保证在try块可以退出之前执行finally块的。当编译程序检查源代码时,它看到在try块中有return语句。这样,编译程序就生成代码将返回值(本例中是5)保存在一个编译程序建立的临时变量中。编译程序然后再生成代码来执行f i n a l l y块中包含的指令,这称为局部展开。更特殊的情况是,由于try块中存在过早退出的代码,从而产生局部展开,导致系统执行finally块中的内容。在finally块中的指令执行之后,编译程序临时变量的值被取出并从函数中返回。

    可以看到,要完成这些事情,编译程序必须生成附加的代码,系统要执行额外的工作。

    finally块的总结性说明

    我们已经明确区分了强制执行finally块的两种情况:

    • 从try块进入finally块的正常控制流。

    • 局部展开:从try块的过早退出(goto、long jump、continue、break、return等)强制控制转移到finally块。

    第三种情况,全局展开( global unwind),这个以后再看。

    七、C++异常参数传递

    从语法上看,在函数里声明参数与在catch子句中声明参数是一样的,catch里的参数可以是值类型,引用类型,指针类型。例如:

    try

    {

    .....

    }

    catch(A a)

    {

    }

    catch(B& b)

    {

    }

    catch(C* c)

    {

    }

    尽管表面是它们是一样的,但是编译器对二者的处理却又很大的不同。调用函数时,程序的控制权最终还会返回到函数的调用处,但是抛出一个异常时,控制权永远不会回到抛出异常的地方。

    class A;

    void func_throw()

    {

    A a;

    throw a; //抛出的是a的拷贝,拷贝到一个临时对象里

    }

    try

    {

    func_throw();

    }

    catch(A a) //临时对象的拷贝

    {

    }

    当我们抛出一个异常对象时,抛出的是这个异常对象的拷贝。当异常对象被拷贝时,拷贝操作是由对象的拷贝构造函数完成的。该拷贝构造函数是对象的静态类型(static type)所对应类的拷贝构造函数,而不是对象的动态类型(dynamic type)对应类的拷贝构造函数。此时对象会丢失RTTI信息。

    异常是其它对象的拷贝,这个事实影响到你如何在catch块中再抛出一个异常。比如下面这两个catch块,乍一看好像一样:

    catch (A& w) // 捕获异常

    {

    // 处理异常

    throw; // 重新抛出异常,让它继续传递

    }

    catch (A& w) // 捕获Widget异常

    {

    // 处理异常

    throw w; // 传递被捕获异常的拷贝

    }

    第一个块中重新抛出的是当前异常(current exception),无论它是什么类型。(有可能是A的派生类)

    第二个catch块重新抛出的是新异常,失去了原来的类型信息。

    一般来说,你应该用throw来重新抛出当前的异常,因为这样不会改变被传递出去的异常类型,而且更有效率,因为不用生成一个新拷贝。

    看看以下这三种声明:

    catch (A w) ... // 通过传值

    catch (A& w) ... // 通过传递引用,一个被异常抛出的对象(总是一个临时对象)可以通过普通的引用捕获

    catch (const A& w) ... //const引用

    catch (A w) ... // 通过传值捕获

    会建立两个被抛出对象的拷贝,一个是所有异常都必须建立的临时对象,第二个是把临时对象拷贝进w中。实际上,编译器会优化掉一个拷贝。同样,当我们通过引用捕获异常时,

    catch (A& w) ... // 通过引用捕获

    catch (const A& w) ... //const引用捕获

    这仍旧会建立一个被抛出对象的拷贝:拷贝是一个临时对象。相反当我们通过引用传递函数参数时,没有进行对象拷贝。话虽如此,但是不是所有编译器都如此。

    通过指针抛出异常与通过指针传递参数是相同的。不论哪种方法都是一个指针的拷贝被传递。你不能认为抛出的指针是一个指向局部对象的指针,因为当异常离开局部变量的生存空间时,该局部变量已经被释放。Catch子句将获得一个指向已经不存在的对象的指针。这种行为在设计时应该予以避免。

    另外一个重要的差异是在函数调用者或抛出异常者与被调用者或异常捕获者之间的类型匹配的过程不同。在函数传递参数时,如果参数不匹配,那么编译器会尝试一个类型转换,如果存在的话。而对于异常处理的话,则完全不是这样。见一下的例子:

    void func_throw()

    {

    CString a;

    throw a; //抛出的是a的拷贝,拷贝到一个临时对象里

    }

    try

    {

    func_throw();

    }

    catch(const char* s)

    {

    }

    尽管如此,在catch子句中进行异常匹配时可以进行两种类型转换。第一种是基类与派生类的转换,一个用来捕获基类的catch子句也可以处理派生类类型的异常。反过来,用来捕获派生类的无法捕获基类的异常。

    第二种是允许从一个类型化指针(typed pointer)转变成无类型指针(untyped pointer),所以带有const void* 指针的catch子句能捕获任何类型的指针类型异常:

    catch (const void*) ... //可以捕获所有指针异常另外,你还可以用catch(...)来捕获所有异常,注意是三个点。

    传递参数和传递异常间最后一点差别是catch子句匹配顺序总是取决于它们在程序中出现的顺序。因此一个派生类异常可能被处理其基类异常的catch子句捕获,这叫异常截获,一般的编译器会有警告。

    class A {

    public:

    A()

    {

    cout << "class A creates" << endl;

    }

    void print()

    {

    cout << "A" << endl;

    }

    ~A()

    {

    cout << "class A destruct" << endl;

    }

    };

    class B: public A

    {

    public:

    B()

    {

    cout << "class B create" << endl;

    }

    void print()

    {

    cout << "B" << endl;

    }

    ~B()

    {

    cout << "class B destruct" << endl;

    }

    };

    void func()

    {

    B b;

    throw b;

    }

    try

    {

    func();

    }

    catch( B& b) //必须将B放前面,如果把A放前面,B放后面,那么B类型的异常会先被截获。

    {

    b.print();

    }

    catch (A& a)

    {

    a.print() ;

    }

    这篇文章就介绍到这了,需要的朋友可以参考一下。

    展开全文
  • php 也有自己的异常处理方法,虽然比不上Java的强大,但是简单的还是很容易处理的。try{$a = 2;echo $a;if($a >...');}echo 'ok';}catch(Exception $e){echo $...}在数据库中使用事物时,用该方法非常方便:$state =...

    php 也有自己的异常处理方法,虽然比不上Java的强大,但是简单的还是很容易处理的。

    try{

    $a = 2;

    echo $a;

    if($a > 200)

    {

    throw new Exception ('更新管理平台密码失败!');

    }

    echo 'ok';

    }

    catch(Exception $e)

    {

    echo $e->getMessage();

    }

    在数据库中使用事物时,用该方法非常方便:

    $state = 0;

    // 添加事物处理

    try {

    // 开启事物

    $GLOBALS['db']->beginTransaction();

    // 更新管理平台密码

    $state = $GLOBALS['db']->query("update admin_user set password='$password_confirm' where user_id=$user_id");

    if($state != true)

    {

    throw new Exception ('更新管理平台密码失败!');

    }

    $ret = $this->modify_ldap_pwd($user_name, $user_password_old, $user_password_confirm);

    if(!$ret)

    {

    throw new Exception ('更新LDAP密码失败!');

    }

    // 提交事物

    $GLOBALS['db']->commit();

    $state = 1;

    }

    catch (Exception $e)

    {

    // 回滚

    $GLOBALS['db']->rollBack();

    }

    函数封装处理:

    define('runcode', 1);

    function testE($num){

    if($num == 1){

    return 'hello';

    }else{

    throw new Exception ( "error");

    }

    }

    try{

    $ret = testE(1);

    dump($ret);

    dump(100);

    } catch (Exception $e ){

    echo $e->getMessage();

    dump('抛出了异常');

    }

    展开全文
  • try、catch、finally用法总结: 1、不管有没有异常,finally中的代码都会执行 2、当try、catch中有return时,finally中的代码依然会继续执行 3、finally是在return后面的表达式运算之后执行的,此时并没有返回运算...

    try、catch、finally用法总结:

    1、不管有没有异常,finally中的代码都会执行

    2、当try、catch中有return时,finally中的代码依然会继续执行

    3、finally是在return后面的表达式运算之后执行的,此时并没有返回运算之后的值,而是把值保存起来,不管finally对该值做任何的改变,返回的值都不会改变,依然返回保存起来的值。也就是说方法的返回值是在finally运算之前就确定了的。

    4、finally代码中最好不要包含return,程序会提前退出,也就是说返回的值不是try或catch中的值

    针对第2、第3点补充代码示例:
     

    	public static void main(String[] args) {
    		System.out.println(test());
    	}
    	public static int test(){
    		int i = 1;
    		try{
    			i++;
    			System.out.println("try block, i = "+i);
    			return i;
    		}catch(Exception e){
    			i ++;
    			System.out.println("catch block i = "+i);
    		}finally{
    			i = 10;
    			System.out.println("finally block i = "+i);
    		}
    		return i;
    	}

    结果输出:
            try block, i = 2
            finally block i = 10
            2
    根据输出结果可以看出 返回的是try块的return i;执行顺序是先try 再执行finally 再执行的try块的return i,只是可以证明第2点,同时证明了第3点(前提是:finally是在return后面的表达式运算之后执行的

    补充示例2(反向验证第3点):

    	public static void main(String[] args) {
    		System.out.println(test());
    	}
    	public static int test(){
    		int i = 1;
    		try{
    			i++;
    			System.out.println("try block, i = "+i);
    		}catch(Exception e){
    			i ++;
    			System.out.println("catch block i = "+i);
    		}finally{
    			i = 10;
    			System.out.println("finally block i = "+i);
    		}
    		return i;
    	}

    结果输出:
            try block, i = 2
            finally block i = 10
            10
    当try、catch中无return,return在 finally 后面时,执行顺序是try  finally return ,返回的是finally 改变的值
     

    示例3
     

    	public static void main(String[] args) {
    		System.out.println(test());
    	}
    	public static int test(){
    		int i = 1;
    		try{
    			i++;
    			System.out.println("try block, i = "+i);
    			return i;
    		}catch(Exception e){
    			i ++;
    			System.out.println("catch block i = "+i);
    		}finally{
    			i = 10;
    			System.out.println("finally block i = "+i);
    			return i;
    		}
    	}

    结果输出:
    try block, i = 2
    finally block i = 10
    10

    当try、catch、finally 中都有return 时,返回的是finally的 里改变的值 执行的是finally  中的return,验证第4点
     

    展开全文
  • 1. try 、catch、finally用法总结 1、在进行异常的处理之后,在异常的处理格式中还有一个finally语句,那么此语句将作为异常的统一出口,不管是否产生了异常,最终都要执行此段代码。 2、当try、catch中有return时...

    1. try 、catch、finally用法总结

        1、在进行异常的处理之后,在异常的处理格式中还有一个finally语句,那么此语句将作为异常的统一出口,不管是否产生了异常,最终都要执行此段代码。
        2、当try、catch中有return时,finally中的代码依然会继续执行
        3、finally是在return后面的表达式运算之后执行的,此时并没有返回运算之后的值,而是把值保存起来,不管finally对该值做任何的改变,返回的值都不会改变,依然返回保存起来的值。也就是说方法的返回值是在finally运算之前就确定了的。
        4、finally代码中最好不要包含return,程序会提前退出,也就是说返回的值不是try或catch中的值
    
    

    2. try+catch的处理流程

        1、 一旦产生异常,则系统会自动产生一个异常类的实例化对象。
        2、 那么,此时如果异常发生在try语句,则会自动找到匹配的catch语句执行,如果没有在try语句中,则会将异
        常抛出.
        3、 所有的catch根据方法的参数匹配异常类的实例化对象,如果匹配成功,则表示由此catch进行处理。
    

    3. 当我们操作引用数据类型的时候返回值是什么呢?

    public class Demo {
        public static void main(String[] args) {
            Person p = haha();
            System.out.println(p.age);
        }
        public static Person haha(){
            Person p = new Person();
            try {
                p.age = 18;
                return p;   //被保存起来
            }catch (Exception E){
                return null;
            }finally {
                p.age = 28;
            }
    
        }
        static class Person{
            int age;
        }
    }
    
    结果 
    ​	28
    

    总结:

    ​ return p 是把引用数据(堆中)地址保存起来(18),finally再赋值的时候,该地址内容变为28,所以返回28.

    4. 当我们操作数据类型的时候返回值是什么呢?

    public class Demo1 {
        public static void main(String[] args) {
            int a  = haha();
            System.out.println(a);
        }
        public static int haha(){
            int a = 10;
            try {
                return a;   //被保存起来
            }catch (Exception E){
                return 0;
            }finally {
                a = 20;
            }
    
        }
    }
    
    结果
    	10
    

    总结:

    ​ 基本数据类型创建的时候在栈中,当我们返回a的时候会先保存起来,后面finally再赋值的时候,a的值为20,但返回的是被保存起来的值,所以值没有变化,还是10.

    5. 如果在finally添加返回值

    public class Demo1 {
        public static void main(String[] args) {
            int a  = haha();
            System.out.println(a);
        }
        public static int haha(){
            int a = 10;
            try {
                return a;   
            }catch (Exception E){
                return 0;
            }finally {
                a = 20;
                return a;
            }
    
        }
    }
    
    结果
    	20
    

    总结:

    ​ 明显,当try或者catch中有返回值,但是finally中也有返回语句时,最终返回的是finally中的返回值.

    几个面试题:

    1. try-catch-finally 中哪个部分可以省略?
    	答: catch和finally可以省略其中一个 , catch和finally不能同时省略
    	注意:格式上允许省略catch块, 但是发生异常时就不会捕获异常了,我们在开发中也不会这样去写代码.
    2. try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
    	答:finally中的代码会执行
    	详解:
    	执行流程:
    	(1) 先计算返回值, 并将返回值存储起来, 等待返回
    	(2) 执行finally代码块
    	(3) 将之前存储的返回值, 返回出去;
    	需注意:
    	(1) 返回值是在finally运算之前就确定了,并且缓存了,不管finally对该值做任何的改变,返回的值都不
    	会改变
    	(2) finally代码中不建议包含return,因为程序会在上述的流程中提前退出,也就是说返回的值不是try或
    	catch中的值
    	(3) 如果在try或catch中停止了JVM,则finally不会执行.例如停电- -, 或通过如下代码退出
    	JVM:System.exit(0);
    
    展开全文
  • 如果没有提供处理器机制,程序就会终止,并在控制台上打印一条信息,给出异常的类型.L比如:使用了NULL引用或者是数组越界等。异常有两种类型:未检查异常和已检查异常对于已检查异常,处理器器将会检查是否提供了...
  • 本文实例讲述了Python使用try except处理程序异常的三种常用方法。分享给大家供大家参考,具体如下:如果你在写python程序时遇到异常后想进行如下处理的话,一般用try来处理异常,假设有下面的一段程序:try:语句1...
  • try-catch简单用法-事务回滚Transactional

    千次阅读 2021-04-15 16:40:40
    try { PageHelper.startPage(dto.getPageNum(), dto.getPageSize()); List<MdaDataAcquisitionDTO> list = mdaDataAcquisitionService.getPage(dto); PageInfo<MdaDataAcquisitionDTO> pageInfo = ...
  • 使用try…except,这样程序就不会因为异常而中断。把可能发生错误的语句放在try模块里,用except来处理异常。except可以处理一个专门的异常,也可以处理一组圆括号中的异常,如果except后没有指定异常,则默认处理...
  • 我们把可能发生错误的语句放在try模块里,用except来处理异常。except可以处理一个专门的异常,也可以处理一组圆括号中的异常,如果except后没有指定异常,则默认处理所有的异常。每一个try,都必须至少有一个except...
  • 1. 背景其实,在JDK 7就已经引入了对try-with-resources的支持,它的主要作用就是解放小明和小明伙伴们的双手,帮助我们自动释放使用过的资源(比如输入、输出流)。2. 例子如何才能使用这个自动关闭资源的骚操作呢...
  • 欢迎微信搜索公众号【java版web项目】获取资源:java学习视频/设计模式笔记/算法手册/java项目这篇文章是我近期看了《Effective java》一书中总结的,来自其中第九条。为了对其理解的更加透彻,因此重新分析了一下,...
  • 本文实例讲述了Python中的错误和异常处理操作。分享给大家供大家参考,具体如下:#coding=utf8print '''''程序编译时会检测语法错误。...try:try_suiteexcept :except_suite--------------------...
  • try/except与其他语言相同,在python中,try/except语句主要是用于throw程序正常执行过程中出现的异常,如语法错(python作为脚本语言没有编译的环节,在执行过程中对语法进行检测,出错后发出异常消息)、数据除零...
  • try+catch的处理流程异常体系结构throws关键字此关键字主要在方法的声明上使用,表示方法中不处理异常,而交给调用处处理。RuntimeExcepion与Exception的区别注意观察如下方法的源码:Integer类: public static int...
  • Arcgis Engine之try用法

    2021-06-27 09:30:50
    Arcgis Engine之try用法 https://blog.csdn.net/this_tall_people/article/details/76512417 https://www.cnblogs.com/swlq/p/5355341.html ...
  • 对python中try except处理程序异常的三种常用方法感兴趣的伙伴,下面一起跟随512笔记的编两巴掌来看看吧!如果你在写python程序时遇到异常后想进行如下处理的话,一般用try来处理异常,假设有下面的一段程序:try...
  • 问:Java异常处理机制,理解了吗?Java异常处理,真的掌握了吗?什么是自定义异常?catch体里遇到return 是...try catch语句格式:(代码区如果有错误,就会返回到异常处理)1 try{23 //代码区45 }catch(Exception e...
  • 上学的时候,也许老师告诉你用完文件流记得要关闭,可能为了省事,他也没仔细的给你示范如何关闭,实际开发中...流在try外面声明,在try里面初始化,然后在finally里面给close,还记得处理异常efinally里面close的时...
  • Unity使用try-catch

    2021-03-21 19:29:40
    一、目的 ...1、想知道:Unity使用try-catch 二、参考 1、如何在Unity正确的使用try-catch https://blog.csdn.net/ZhangDi2017/article/details/77348838 总结:good:很有意思! 三、操作 1、
  • Java 中最常见的异常处理机制通常与 try-catch 块关联 。我们使用它来捕获异常,然后提供在发生异常的情况下可以执行的逻辑。的确,你不需要将所有异常都放在这些块中。另一方面,如果你正在研究应用程序的软件设计...
  • 多个嵌套的try…catch…finally

    千次阅读 2021-03-09 08:59:56
    请先阅读 EmbedeFinally.java示例,再运行它,观察其输出并进行总结源代码:publicclassEmbededFinally{publicstaticvoidmain(Stringargs[]){intresult;try{System.out.println("inLevel1");try{System.out.println...
  • php try catch throw 用法

    2021-03-23 20:27:27
    1.try catch 捕捉不到fatal error致命错误2.只有抛出异常才能被截获,如果异常抛出了却没有被捕捉到,就会产生一个fatal error。3.父类可以捕获抛出的子类异常,Exception 可以捕获继承Exception 类型的异常class ...
  • 异常 定义 表示程序在运行过程中出现的非正常情况,编写代码的过程中尽可能少的减少异常出现的情况 分类 Throwable Error 代码级别无法解决的异常情况 Exception 运行时异常:在程序运行过程中,由于...try{
  • 异常处理的机制如下:在方法中用 try... catch... 语句捕获并处理异常,catch 语句可以有多个,用来匹配多个不同类型的异常。对于处理不了的异常或者要转型的异常,在方法的声明处通过 throws 声明异常,通过throw.....

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 373,448
精华内容 149,379
关键字:

try的用法总结