不要在finally塊中處理返回值,面試中經常出現的題目

在finally代碼塊中處理返回值,這是考試和麵試中經常出現的題目。雖然可以以此來出考試題,但在項目中絕對不能再finally代碼塊中出現return語句,這是因為這種處理方式非常容易產生" 誤解 ",會誤導開發者。例如如下代碼:

不要在finally塊中處理返回值,面試中經常出現的題目

對於這段代碼,有兩個問題:main方法中的doStuff方法的返回值是什麼?doStuff方法永遠都不會拋出異常嗎?

答案是:doStuff(-1)的值是-1,doStuff(100)的值也是-1,調用doStuff方法永遠都不會拋出異常,有這麼神奇?原因就是我們在finally代碼塊中加入了return語句,而這會導致出現以下兩個問題:

(1)、覆蓋了try代碼塊中的return返回值

當執行doStuff(-1)時,doStuff方法產生了DataFormatException異常,catch塊在捕捉此異常後直接拋出,之後代碼執行到finally代碼塊,就會重置返回值,結果就是-1了。也就是出現先返回,再重置返回的情況。

有人可能會思考,是不是可以定義變量,在finally中修改後return呢?代碼如下:

不要在finally塊中處理返回值,面試中經常出現的題目

該方法的返回值永遠是1,不會是-1或0(為什麼不會執行到" return 0 " 呢?原因是finally執行完畢後該方法已經有返回值了,後續代碼就不會再執行了),這都是源於異常代碼塊的處理方式,在代碼中try代碼塊就標誌著運行時會有一個Throwale線程監視著該方法的運行,若出現異常,則交由異常邏輯處理。

我們知道方法是在棧內存中運行的,並且會按照“ 先進後出 ”的原則執行,main方法調用了doStuff方法,則main方法在下層,doStuff方法在上層,當doStuff方法執行完" return a " 時,此方法的返回值已經確定int類型1(a變量的值,注意基本類型都是拷貝值,而不是引用),此時finally代碼塊再修改a的值已經與doStuff返回者沒有任何關係了,因此該方法永遠都會返回1.

繼續追問,那是不是可以在finally代碼塊中修改引用類型的屬性以達到修改返回值的效果呢?代碼如下:

不要在finally塊中處理返回值,面試中經常出現的題目

不要在finally塊中處理返回值,面試中經常出現的題目

此方法的返回值永遠都是name為李四的Person對象,原因是Person是一個引用對象,在try代碼塊中的返回值是Person對象的地址,finally中再修改那當然會是李四了。

(2)、屏蔽異常

為什麼明明把異常throw出去了,但main方法卻捕捉不到呢?這是因為異常線程在監視到有異常發生時,就會登記當前的異常類型為DataFormatException,但是當執行器執行finally代碼塊時,則會重新為doStuff方法賦值,也就是告訴調用者" 該方法執行正確,沒有產生異常,返回值為1 ",於是乎,異常神奇的消失了,其簡化代碼如下所示:

不要在finally塊中處理返回值,面試中經常出現的題目

不要在finally塊中處理返回值,面試中經常出現的題目

上面finally代碼塊中的return已經告訴JVM:doSomething方法正常執行結束,沒有異常,所以main方法就不可能獲得任何異常信息了。這樣的代碼會使可讀性大大降低,讀者很難理解作者的意圖,增加了修改的難度。

在finally中處理return返回值,代碼看上去很完美,都符合邏輯,但是執行起來就會產生邏輯錯誤,最重要的一點是finally是用來做異常的收尾處理的,一旦加上了return語句就會讓程序的複雜度徒然上升,而且會產生一些隱蔽性非常高的錯誤。

與return語句相似,System.exit(0)或RunTime.getRunTime().exit(0)出現在異常代碼塊中也會產生非常多的錯誤假象,增加代碼的複雜性,大家有興趣可以自行研究一下。

  注意:不要在finally代碼塊中出現return語句。

有討論,才有進步,大家各抒己見,讓每位同學學到不一樣的!


分享到:


相關文章: