下面的程序循環(huán)遍歷了一個(gè)int類型的數(shù)組序列,并且記錄了滿足某個(gè)特定屬性的數(shù)組個(gè)數(shù)。那么,該程序會(huì)打印出什么呢?
public class Loop {
public static void main(String[] args) {
int[][] tests = { { 6, 5, 4, 3, 2, 1 }, { 1, 2 },
{ 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 } };
int successCount = 0;
try {
int i = 0;
while (true) {
if (thirdElementIsThree(tests[i++]))
successCount ++;
}
} catch(ArrayIndexOutOfBoundsException e) {
// No more tests to process
}
System.out.println(successCount);
}
private static boolean thirdElementIsThree(int[] a) {
return a.length >= 3 & a[2] == 3;
}
}
該程序用thirdElementIsThree方法測(cè)試了tests數(shù)組中的每一個(gè)元素。遍歷這個(gè)數(shù)組的循環(huán)顯然是非傳統(tǒng)的循環(huán):它不是在循環(huán)變量等于數(shù)組長(zhǎng)度的時(shí)候終止,而是在它試圖訪問一個(gè)并不在數(shù)組中的元素時(shí)終止。盡管它是非傳統(tǒng)的,但是這個(gè)循環(huán)應(yīng)該可以工作。如果傳遞給thirdElementIsThree的參數(shù)具有3個(gè)或更多的元素,并且其第三個(gè)元素等于3,那么該方法將返回true。對(duì)于tests中的5個(gè)元素來說,有2個(gè)將返回true,因此看起來該程序應(yīng)該打印2。如果你運(yùn)行它,就會(huì)發(fā)現(xiàn)它打印的時(shí)0??隙ㄊ悄睦锍隽藛栴},你能確定嗎?
事實(shí)上,這個(gè)程序犯了兩個(gè)錯(cuò)誤。第一個(gè)錯(cuò)誤是該程序使用了一種可怕的循環(huán)慣用法,該慣用法依賴的是對(duì)數(shù)組的訪問會(huì)拋出異常。這種慣用法不僅難以閱讀,而且運(yùn)行速度還非常地慢。不要使用異常來進(jìn)行循環(huán)控制;應(yīng)該只為異常條件而使用異常[EJ Item 39]。為了糾正這個(gè)錯(cuò)誤,可以將整個(gè)try-finally語(yǔ)句塊替換為循環(huán)遍歷數(shù)組的標(biāo)準(zhǔn)慣用法:
for (int i = 0; i < test.length; i++)
if (thirdElementIsThree(tests[i]))
successCount++;
如果你使用的是5.0或者是更新的版本,那么你可以用for循環(huán)結(jié)構(gòu)來代替:
for (int[] test : tests)
if(thirdElementIsThree(test))
successCount++;
就第一個(gè)錯(cuò)誤的糟糕情況來說,只有它自己還不足以產(chǎn)生我們所觀察到的行為。然而,訂正該錯(cuò)誤可以幫助我們找到真正的bug,它更加深?yuàn)W:
Exception in thread "main"
java.lang.ArrayIndexOutOfBoundsException: 2
at Loop1.thirdElementIsThree(Loop1.java:19)
at Loop1.main(Loop1.java:13)
很明顯,在thirdElementIsThree方法中有一個(gè)bug:它拋出了一個(gè)ArrayIndexOutOfBoundsException異常。這個(gè)異常先前偽裝成了那個(gè)可怕的基于異常的循環(huán)的終止條件。
如果傳遞給thirdElementIsThree的參數(shù)具有3個(gè)或更多的元素,并且其第三個(gè)元素等于3,那么該方法將返回true。問題是在這些條件不滿足時(shí)它會(huì)做些什么呢。如果你仔細(xì)觀察其值將會(huì)被返回的那個(gè)布爾表達(dá)式,你就會(huì)發(fā)現(xiàn)它與大多數(shù)布爾AND操作有一點(diǎn)不一樣。這個(gè)表達(dá)式是a.length >= 3 & a[2] == 3。通常,你在這種情況下看到的是 && 操作符,而這個(gè)表達(dá)式使用的是 & 操作符。那是一個(gè)位AND操作符嗎?
public class Loop {
public static void main(String[] args) {
int[][] tests = { { 6, 5, 4, 3, 2, 1 }, { 1, 2 },
{ 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 } };
int successCount = 0;
try {
int i = 0;
while (true) {
if (thirdElementIsThree(tests[i++]))
successCount ++;
}
} catch(ArrayIndexOutOfBoundsException e) {
// No more tests to process
}
System.out.println(successCount);
}
private static boolean thirdElementIsThree(int[] a) {
return a.length >= 3 & a[2] == 3;
}
}
該程序用thirdElementIsThree方法測(cè)試了tests數(shù)組中的每一個(gè)元素。遍歷這個(gè)數(shù)組的循環(huán)顯然是非傳統(tǒng)的循環(huán):它不是在循環(huán)變量等于數(shù)組長(zhǎng)度的時(shí)候終止,而是在它試圖訪問一個(gè)并不在數(shù)組中的元素時(shí)終止。盡管它是非傳統(tǒng)的,但是這個(gè)循環(huán)應(yīng)該可以工作。如果傳遞給thirdElementIsThree的參數(shù)具有3個(gè)或更多的元素,并且其第三個(gè)元素等于3,那么該方法將返回true。對(duì)于tests中的5個(gè)元素來說,有2個(gè)將返回true,因此看起來該程序應(yīng)該打印2。如果你運(yùn)行它,就會(huì)發(fā)現(xiàn)它打印的時(shí)0??隙ㄊ悄睦锍隽藛栴},你能確定嗎?
事實(shí)上,這個(gè)程序犯了兩個(gè)錯(cuò)誤。第一個(gè)錯(cuò)誤是該程序使用了一種可怕的循環(huán)慣用法,該慣用法依賴的是對(duì)數(shù)組的訪問會(huì)拋出異常。這種慣用法不僅難以閱讀,而且運(yùn)行速度還非常地慢。不要使用異常來進(jìn)行循環(huán)控制;應(yīng)該只為異常條件而使用異常[EJ Item 39]。為了糾正這個(gè)錯(cuò)誤,可以將整個(gè)try-finally語(yǔ)句塊替換為循環(huán)遍歷數(shù)組的標(biāo)準(zhǔn)慣用法:
for (int i = 0; i < test.length; i++)
if (thirdElementIsThree(tests[i]))
successCount++;
如果你使用的是5.0或者是更新的版本,那么你可以用for循環(huán)結(jié)構(gòu)來代替:
for (int[] test : tests)
if(thirdElementIsThree(test))
successCount++;
就第一個(gè)錯(cuò)誤的糟糕情況來說,只有它自己還不足以產(chǎn)生我們所觀察到的行為。然而,訂正該錯(cuò)誤可以幫助我們找到真正的bug,它更加深?yuàn)W:
Exception in thread "main"
java.lang.ArrayIndexOutOfBoundsException: 2
at Loop1.thirdElementIsThree(Loop1.java:19)
at Loop1.main(Loop1.java:13)
很明顯,在thirdElementIsThree方法中有一個(gè)bug:它拋出了一個(gè)ArrayIndexOutOfBoundsException異常。這個(gè)異常先前偽裝成了那個(gè)可怕的基于異常的循環(huán)的終止條件。
如果傳遞給thirdElementIsThree的參數(shù)具有3個(gè)或更多的元素,并且其第三個(gè)元素等于3,那么該方法將返回true。問題是在這些條件不滿足時(shí)它會(huì)做些什么呢。如果你仔細(xì)觀察其值將會(huì)被返回的那個(gè)布爾表達(dá)式,你就會(huì)發(fā)現(xiàn)它與大多數(shù)布爾AND操作有一點(diǎn)不一樣。這個(gè)表達(dá)式是a.length >= 3 & a[2] == 3。通常,你在這種情況下看到的是 && 操作符,而這個(gè)表達(dá)式使用的是 & 操作符。那是一個(gè)位AND操作符嗎?