天天看點

Try,Catch,Finally三塊中如果有Return是怎麼個運作順序

     今天看一個Java SSH的面試題,題目大概意思是:try、catch中存在return語句,還會執行finally塊嗎?如果執行,是return先執行還是finally先執行?如果有多個return語句,結果如何?

     看了以後我還真犯嘀咕,做了軟體開發這些年,還沒認真思考過則個問題,于是趕緊寫個測試測試代碼如下:

1 class Program
 2     {
 3         public static int a = 0;
 4         static void Main(string[] args)
 5         {
 6             var result = GetValue();
 7         }
 8 
 9         public static int GetValue()
10         {
11             try
12             {
13                 a = 2;
14                 throw new Exception();
15             }
16             catch (Exception ex)
17             {
18                 a = 3;
19                 return a;
20                 a = 4;
21             }
22             finally
23             {
24                 a = 5;
25             }
26         }
27     }      

為了探究個明白,使用ILSpy工具檢視IL代碼, GetValue()的IL代碼如下:

1 .method public hidebysig static 
 2     int32 GetValue () cil managed 
 3 {
 4     // Method begins at RVA 0x2064
 5     // Code size 42 (0x2a)
 6     .maxstack 1   
 7     .locals init (   
 8         [0] class [mscorlib]System.Exception ex,//定義Exception類型變量 ex
 9         [1] int32 CS$1$0000                     //定義int32類型變量 CS$1$000        
10     )
11 
12     IL_0000: nop                                //No Operation 沒有任何操作
13     .try
14     {
15         .try
16         {
17             IL_0001: nop
18             IL_0002: ldc.i4.2                   //把int32 類型的資料2 推入計算堆棧上
19             IL_0003: stsfld int32 ConsoleApplication1.Program::a                      //用計算堆棧的值替換靜态字段a的值
20             IL_0008: newobj instance void [mscorlib]System.Exception::.ctor()         //執行個體化Exception對象,并将對象推入到計算堆棧上
21             IL_000d: throw                      //引發目前位于計算堆棧上的異常對象
22         } // end .try
23         catch [mscorlib]System.Exception
24         {
25             IL_000e: stloc.0                    //從計算堆棧的頂部彈出目前值(Exception對象)并将其存儲到索引 0 處的局部變量清單中
26             IL_000f: nop
27             IL_0010: ldc.i4.3                   //把整數類型3推入計算堆棧上
28             IL_0011: stsfld int32 ConsoleApplication1.Program::a                     //用計算堆棧的值置換靜态變量a的值
29             IL_0016: ldsfld int32 ConsoleApplication1.Program::a                     //将靜态字段a的值推入計算堆棧上
30             IL_001b: stloc.1                    //從計算堆棧的頂部彈出目前值,并将其存儲到索引 1 處的局部變量清單中
31             IL_001c: leave.s IL_0027            //退出受保護的代碼區域,無條件将控制轉移到目标指令 [ leave.s 指令清空計算堆棧并確定執行周圍适當的 finally 塊。]
32         } // end handler
33     } // end .try
34     finally
35     {
36         IL_001e: nop
37         IL_001f: ldc.i4.5                       //把整數5推入計算堆棧上
38         IL_0020: stsfld int32 ConsoleApplication1.Program::a                        //用計算對象韓的值置換靜态變量a的值
39         IL_0025: nop
40         IL_0026: endfinally                     //将控制從異常塊的 fault 或 finally 子句轉移回公共語言結構 (CLI) 異常處理程式。
41     } // end handler
42 
43     IL_0027: nop
44     IL_0028: ldloc.1                            //将索引 1 處的局部變量加載到計算堆棧上
45     IL_0029: ret                                //從目前方法傳回,并将傳回值(如果存在)從調用方的計算堆棧推送到被調用方的計算堆棧上
46 } // end of method Program::GetValue      

通過IL代碼和相關的注釋,基本可以看出他們的執行流程,猜測出這個方法傳回的結果以及靜态變量a最後的值是多少。

最後GetValue()方法傳回的結果是3;靜态變量a的值是5;

Try,Catch,Finally三塊中如果有Return是怎麼個運作順序
Try,Catch,Finally三塊中如果有Return是怎麼個運作順序

但是 “IL_001c: leave.s IL_0027 ”  leave.s 還沒看明白怎麼回事?有相關熟悉的人,請指點,謝謝!

另外問題提到:有多個return的情況,傳回哪個return的結果?  我試了一下,沒有發現允許執行多次return的可能!如果有請不吝指出!

上一篇: BaaS簡介
下一篇: More 平台