文章目錄
First point :finally和return的小細節回顧
在 finally 代碼塊中改變返回值並不會改變最後返回的內容。且它一定會被執行!
總結爲以下幾條:
- 1、當 try 代碼塊和 catch 代碼塊中
有 return 語句時,finally 仍然會被執行。
- 2、執行 try 代碼塊或 catch 代碼塊中的
return 語句之前,都會先執行 finally 語句。
- 3、無論在 finally 代碼塊中是否修改返回值,返回值都不會改變,
仍然是執行 finally 代碼塊之前的值。finally 代碼塊中的 return 語句一定會執行。
- 4、當 finally 有返回值時,會直接返回該值,不會去返回 try 代碼塊或者 catch 代碼塊中的返回值。
注意:finally 代碼塊中最好不要包含 return 語句,否則程序會提前退出。
例子
1、
第一點
:當 try 代碼塊或者 catch 代碼塊中有 return 語句時,finally 仍然會被執行。
第二點
:執行 try 代碼塊或 catch 代碼塊中的 return 語句之前,都會先執行 finally 語句。
public class FinallyAndReturnAndThrow {
public static void main(String[]args){
System.out.println(test1());
System.out.println(test2());
}
private static int test1() {//try帶return
try{
return 1;
}finally {
System.out.println("finally1");
}
}
private static int test2() {//try和catch都有return
try{
System.out.println("haha"+1/0);
return 4;
}catch(Exception e){
return 2;
}finally {
System.out.println("finally2");
}
}
}
先打印finally,纔打印返回值。也就是return是最後執行的!
2、
第四點
:當 finally 有返回值時,會直接返回該值,不會去返回 try 代碼塊或者 catch 代碼塊中的返回值。
注意:finally 代碼塊中最好不要包含 return 語句,否則程序會提前退出。
private static int test3() {//當finally中有返回值則直接返回,不再去執行try或者catch的return
try{
System.out.println("try語句");
return 1;
}catch(Exception e){
return 2;
}finally {
System.out.println("finally4");
return 3;
}
}
先執行try中的代碼,在return語句之前先執行finally
,而finally中直接返回return 3;此時finally執行完不會去執行try或者catch中的return;
3、
第三點
:無論在 finally 代碼塊中是否修改返回值,返回值都不會改變
,仍然是執行 finally 代碼塊之前的值。finally 代碼塊中的 return 語句一定會執行。
private static int test4() {
int result=0;
try{
System.out.println("try語句"+1/result);//拋出異常
return result;
}catch(Exception e){//捕抓
return result+1;
}finally {
System.out.println("finally3");
result=100;
System.out.println(result);//打印100後就會去執行try的return
}
}
雖然finally中修改了result的值,但是執行try中的return result是之前的result值 1。
我猜想是利用了彈棧的效果來實現。
所以當 try 代碼塊或 catch 代碼塊中的 return 返回值類型爲普通變量或引用變量時,即使在後面 finally 代碼塊中對返回值的變量重新賦值,也不會影響最後返回的值。
One question——finally塊中使用return會抑制異常的冒泡傳輸
代碼一:
package 面試題;
/**
* finally塊中使用return會抑制異常的冒泡傳輸
*/
public class FinallyReturnAndThrow2 {
public static void main(String[]args){
div();
}
private static void div() {
try{
System.out.println(1/0);
}catch (Exception e){
System.out.println("div's catch");
throw e;
}finally {
System.out.println("div's finally");
}
}
}
這段代碼會拋出異常(除數爲0)
現在使用一個方法去調用div()
package 面試題;
/**
* finally塊中使用return會抑制異常的冒泡傳輸
*/
public class FinallyReturnAndThrow2 {
public static void main(String[]args){
displayTest();
}
private static void displayTest() {
try{
div();//調用上面的div方法
}catch (Exception e){
System.out.println("displayTest's catch");
}finally {
System.out.println("displayTest's finally");
}
}
private static void div() {
try{
System.out.println(1/0);
}catch (Exception e){
System.out.println("div's catch");
throw e;
}finally {
System.out.println("div's finally");
}
}
}
結果很正常,成功處理了div中拋出的異常
現在在div()中的finally中添加了return 2;
private static int div() {
try{
System.out.println(1/0);
}catch (Exception e){
System.out.println("div's catch");
throw e;
}finally {
System.out.println("div's finally");
return 2;
}
}
再次運行:
package 面試題;
/**
* finally塊中使用return會抑制異常的冒泡傳輸
*/
public class FinallyReturnAndThrow2 {
public static void main(String[]args){
displayTest();
}
private static void displayTest() {
try{
div();
}catch (Exception e){
System.out.println("displayTest's catch");
}finally {
System.out.println("displayTest's finally");
}
}
private static int div() {
try{
System.out.println(1/0);
}catch (Exception e){
System.out.println("div's catch");
throw e;
}finally {
System.out.println("div's finally");
return 2;//添加了返回值
}
}
}
發現沒有catch到異常!即:finally塊中的return語句會阻止異常的棧調用傳輸,使調用者(displayTest)認爲該方法已經正常返回
Second point:finally中可能拋出的異常如何處理?
先來看一段代碼:
package Stream_IntOut;
import java.io.*;
/**
* 使用緩衝區輸入流和緩衝區輸出流實現複製文件的功能。
* 並簡單處理IO異常
*
*/
public class Practice3_BufferedWriter_BufferedReader_Copy {
public static void main(String[]args){
FileWriter fw = null;
FileReader fr = null;
BufferedWriter bufw = null;
BufferedReader bufr = null;
try{
fw = new FileWriter("E:\\file_copy2.txt");
fr = new FileReader("E:\\file.txt");
bufw = new BufferedWriter(fw);
bufr = new BufferedReader(fr);
String line;
while((line=bufr.readLine())!=null){
bufw.write(line);
//寫入換行符
bufw.newLine();
//刷新一次流對象
bufw.flush();
}
}catch(IOException e){
e.printStackTrace();
}finally {
if(fr!=null)
try{
assert bufr != null;
bufr.close();
}catch (IOException e){
throw new RuntimeException("無法關閉fr流對象");
}
if(fw!=null)
try{
assert bufw != null;
bufw.close();
}catch (IOException e){
throw new RuntimeException("無法關閉fw流對象");
}
}
}
}
我們可以從IDEA的提示裏邊看到一些東西:
finally塊裏邊拋出異常是不建議的,java異常語句中的finally塊通常用來做資源釋放操作,如關閉文件、關閉網絡連接、關閉數據庫連接等;finally塊和普通代碼塊一樣,無法同時使用return語句和throw語句,因爲無法通過編譯
正常情況下finally語句中不應該使用return語句,也不應該拋出異常!
首先我們先明確爲什麼不被建議?——finally塊中的throw語句會覆蓋try和catch語句中的異常
先來看一個實例代碼:
package 面試題;
public class FinallyAndReturnAndThrow3 {
public static void main(String[]args){
displayTest();
}
private static void displayTest() {
try{
System.out.println(2/0);//異常發生
}catch (Exception e){
System.out.println("displayTest's catch");
throw new RuntimeException("除數爲0");
}finally {
System.out.println("displayTest's finally");
throw new RuntimeException("俺會覆蓋catch的異常");
}
}
}
catch的異常並沒有被拋出。同樣的try中捕抓的異常也會被掩蓋。
回到上面的問題,我們使用IO流時,常常在finally使用到throw,那該如何解決呢?
以下是目前我所知道的:(待了解深入再跟進。)
第一點:可以將拋出的異常寫到日誌中去,在catch語句塊中寫入。
第二點:對於可能空的變量操作,我們一定要去做if判斷之後再進行響應的操作;
第三點:在Java核心技術書中,作者建議在finally塊中儘量不要使用會拋出異常的資源回收語句。
也就是這裏的close操作儘量不要出現異常
所以我在上面的代碼中加了很多判斷null的操作。