在網(wǎng)上看到一些異常處理的面試題,試著總結(jié)一下矢空,先看下面代碼航罗,把這個(gè)方法在main中進(jìn)行調(diào)用打印返回結(jié)果,看看結(jié)果輸出什么屁药。
public static int testBasic(){
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;
}
沒錯(cuò)粥血,會(huì)按照順序執(zhí)行,先執(zhí)行try內(nèi)代碼段者祖,沒有異常的話進(jìn)入finally立莉,最后返回,那么輸出如下:
try block, i = 2
finally block i = 10
main test i = 10
這個(gè)沒有問題七问,如果我們把return語句放入try catch里又會(huì)怎么樣呢?
public static int testBasic(){
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);
return i;
}finally{
i = 10;
System.out.println("finally block i = "+i);
}
}
輸出結(jié)果是:
try block, i = 2
finally block i = 10
main test i = 2
代碼順序執(zhí)行從try到finally蜓耻,由于finally是無論如何都會(huì)執(zhí)行的,所以try里的語句并不會(huì)直接返回械巡。在try語句的return塊中刹淌,return返回的引用變量并不是try語句外定義的引用變量i,而是系統(tǒng)重新定義了一個(gè)局部引用i’,這個(gè)引用指向了引用i對(duì)應(yīng)的值讥耗,也就是2有勾,即使在finally語句中把引用i指向了值10,因?yàn)閞eturn返回的引用已經(jīng)不是i,而是i',所以引用i的值和try語句中的返回值無關(guān)了古程。
但是蔼卡,這只是一部分,如果把i換成包裝類型而不是基本類型呢挣磨,來看看輸出結(jié)果怎樣雇逞,示例如下:
public static List<Object> testWrap(){
List<Object> list = new ArrayList<>();
try{
list.add("try");
System.out.println("try block");
return list;
}catch(Exception e){
list.add("catch");
System.out.println("catch block");
return list;
}finally{
list.add("finally");
System.out.println("finally block ");
}
}
打印結(jié)果如下:
try block
finally block
main test i = [try, finally]
可以看到荤懂,finally里對(duì)list集合的操作生效了,這是為什么呢塘砸。我們知道基本類型在棧中存儲(chǔ)节仿,而對(duì)于非基本類型是存儲(chǔ)在堆中的,返回的是堆中的地址掉蔬,因此內(nèi)容被改變了廊宪。
好了,現(xiàn)在我們?cè)趂inally里加一個(gè)return女轿,看看語句是從哪里返回的箭启。
public static int testBasic(){
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);
return i;
}finally{
i = 10;
System.out.println("finally block i = "+i);
return i;
}
}
輸出結(jié)果如下:
try block, i = 2
finally block i = 10
main test i = 10
可以看到,是從finally語句塊中返回的谈喳〔崃遥可見,JVM是忽略了try中的return語句婿禽。但I(xiàn)DE中會(huì)對(duì)finally中加的return有黃色警告提示赏僧,這是為什么呢,在try里加入一行會(huì)執(zhí)行異常的代碼扭倾,如下:
public static int testBasic(){
int i = 1;
try{
i++;
int m = i / 0 ;
System.out.println("try block, i = "+i);
return i;
}catch(Exception e){
i ++;
System.out.println("catch block i = "+i);
return i;
}finally{
i = 10;
System.out.println("finally block i = "+i);
return i;
}
}
打印結(jié)果如下:
catch block i = 3
finally block i = 10
main test i = 10
可以看到淀零,因?yàn)閒inally中有return語句,try膛壹、catch中的異常被消化掉了驾中,屏蔽了異常的發(fā)生,這與初期使用try模聋、catch的初衷是相違背的肩民,因此編譯器也會(huì)提示警告。
那如果在finally中有異常發(fā)生链方,會(huì)對(duì)try持痰、catch中的異常有什么影響呢?
public static int testBasic(){
int i = 1;
try{
i++;
Integer.parseInt(null);
System.out.println("try block, i = "+i);
return i;
}catch(Exception e){
String.valueOf(null);
System.out.println("catch block i = "+i);
return i;
}finally{
i = 10;
int m = i / 0;
System.out.println("finally block i = "+i);
}
}
這里我們?cè)趖ry祟蚀、catch里強(qiáng)行加上異常語句工窍,打印結(jié)果如下:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at tryandcatch.TryAndCatch.testBasic(TryAndCatch.java:25)
at tryandcatch.TryAndCatch.main(TryAndCatch.java:45)
這個(gè)提示表示的是finally里的異常信息,也就是說一旦finally里發(fā)生異常前酿,try患雏、catch里的異常信息即被消化掉了,也達(dá)不到異常信息處理的目的罢维。
總結(jié)以上測(cè)試:
1淹仑、finally語句總會(huì)執(zhí)行
2、如果try、catch中有return語句匀借,finally中沒有return取试,那么在finally中修改除包裝類型和靜態(tài)變量、全局變量以外的數(shù)據(jù)都不會(huì)對(duì)try怀吻、catch中返回的變量有任何的影響(包裝類型、靜態(tài)變量會(huì)改變初婆、全局變量)
3蓬坡、盡量不要在finally中使用return語句,如果使用的話磅叛,會(huì)忽略try屑咳、catch中的返回語句,也會(huì)忽略try弊琴、catch中的異常兆龙,屏蔽了錯(cuò)誤的發(fā)生
4、finally中避免再次拋出異常敲董,一旦finally中發(fā)生異常紫皇,代碼執(zhí)行將會(huì)拋出finally中的異常信息,try腋寨、catch中的異常將被忽略
所以在實(shí)際項(xiàng)目中聪铺,finally常常是用來關(guān)閉流或者數(shù)據(jù)庫資源的,并不額外做其他操作萄窜。
注意String new 和 "" 是不一樣的铃剔。
1.String str1 = "abc";
String str2 = "abc";
sysout(str1==str2) 為 TRUE
解釋:棧中str1和str2都直接指向常量池中“abc”,==比較地址查刻,地址一樣键兜。
String str1 = "abc";
String str2 = new String(“abc”);
sysout(str1==str2)穗泵;為FALSE
解釋:str1指向常量池中“abc”普气,str2指向堆中新開辟的空間,所以地址不一樣火欧。
String str1 = "abc";
Stirng str2 = “ab”棋电;
str2=str2+“c”;
sysout(str1==str2)苇侵;為FALSE
解釋:str1指向常量池“abc”赶盔,str2指向堆中新開辟的空間,故地址不同榆浓。
String str1 = new String(“abc”)于未;
String str2 = new String(“abc”);
sysout(str1==str2);為FALSE
解釋:str1指向堆中開辟的空間烘浦,str2在堆中又重新開辟了空間抖坪,兩者并不是同一個(gè)空間,故地址不同闷叉。