1. 程式人生 > >Java流程控制的陷阱——if語句和迴圈體的陷阱

Java流程控制的陷阱——if語句和迴圈體的陷阱

3、if語句的陷阱

3、1 else隱含的條件

       else字面意義是“否則”,隱含的條件是前面條件都不符合,也就是else有一個隱含的條件,else if的條件是if顯示條件和else隱式條件的交集。
public class IfErrorTest {
	public static void main(String[] args) {
		int age = 45;
		if ( age > 20 ) {
			System.out.println("青年人");
		}
		else if ( age > 40 ) {
			System.out.println("中年人");
		}
		else if ( age > 60 ) {
			System.out.println("老年人");
		}
	}
}
輸出結果為: 青年人        上面的程式是試圖根據年齡來判斷屬於青年人、中年人還是老年人。從表面上來看,程式的執行過程為:年齡大於20歲是青年人,年齡大於40歲的是中年人,年齡大於60歲的是老年人。但是最終輸出的卻是青年人。造成這個問題的原因就是else後的隱含條件,else的隱含條件就是不滿足else之前的條件。換句話來說,上面的程式碼實質上等於如下程式碼。
public class IfErrorTest {
	public static void main(String[] args) {
		int age = 45;
		if ( age > 20 ) {
			System.out.println("青年人");
		}
		else if ( age > 40 && !(age > 20)) {
			System.out.println("中年人");
		}
		else if ( age > 60 && !(age > 40) ) {
			System.out.println("老年人");
		}
	}
}
       這樣就比較容易看出為什麼會發生上面的錯誤。對於判斷中年人和老年人的情況是永遠不會發生的,因此,程式也永遠不可能打印出中年人和老年人。為了能夠達到預期的效果,將程式修改為如下所示。
public class IfRightTest {
	public static void main(String[] args) {
		int age = 45;
		if ( age > 60 ) {
			System.out.println("老年人");
		}
		else if ( age > 40 ) {
			System.out.println("中年人");
		}
		else if ( age > 20 ) {
			System.out.println("青年人");
		}
	}
}
輸出結果為: 中年人        上面程式的判斷邏輯可以轉換為如下三種情形。
  1. age大於60,判斷為“老年人”。
  2. age大於40歲,且age小於等於60歲,判斷為“中年人”。
  3. age大於20歲,且age小於等於40歲,判斷為“青年人”。

       如果每次都去計算if條件和else條件的交集也是一件非常繁瑣的事情,為了避免出現上面的錯誤,使用if-else語句有一條基本原則: 總是優先把包含範圍小的條件放在前面處理。例如age>60比age>20的範圍更小,所以應該優先處理age>60的情況。

3、2 空語句

public class BlankStatement {
	public static void main(String[] args) {
		int age = 45;
		if ( age > 60 ); {
			System.out.println("老年人");
		}
		else if ( age > 40 ) {
			System.out.println("中年人");
		}
		else if ( age > 20 ) {
			System.out.println("青年人");
		}
	}

}
從表面上來看,這個程式應該一切正常,程式先處理小範圍條件,後處理大範圍的條件,應該輸出“青年人”,但是程式卻報錯:Syntax error on token "else", delete this token。原因是:if ( age > 60 );,在判斷之後有一個分號,這個分號就是一個空語句。也就是說,這個分號就是if語句的條件執行體,if語句到這裡就完全結束了。 需要指出的是,如果if語句後沒有花括號括起來的條件執行體,那麼這個if語句僅僅控制到該語句後的第一個分號處,後面部分將不再受該if語句的控制

4、迴圈體的陷阱

4、1 迴圈體花括號

       Java對於if語句、while語句、for語句的處理策略完全一樣:如果緊跟該語句的是花括號括起來的語句塊,那麼該 if語句、while語句、for語句將控制花括號括起來的語句塊;如果if語句、while語句、for語句之後沒有緊跟花括號,那麼if語句、while語句、for語句的作用範圍到該語句之後的第一個分號結束。
public class WhileScopeTest {
	public static void main(String[] args) {
		int i = 0 ; 
		while ( i < 10 ) 
			System.out.println(i);
			i ++;
	}
}
       上面程式編譯正常,執行時一直輸出0,並且是一個死迴圈。出現這個輸出結果是因為程式省略了while迴圈的迴圈體花括號,那麼受while迴圈控制的迴圈體只有一行程式碼System.out.println(i);。接下來的i++;並不在迴圈體之內,將導致迴圈計數器i一直保持0。        只有當迴圈體內只包含一條語句時才可以省略迴圈體的花括號,此時迴圈本身不會受到太大的影響。當迴圈體有多條語句時,不可省略迴圈體的花括號,否則迴圈體將變成只有緊跟迴圈條件的那條語句。

4、2 省略花括號的危險

class Cat {
	private static long instance = 0;
	
	public Cat() {
		System.out.println("執行無引數的構造器");
		instance++;
	}
	
	public static long getInstance() {
		return instance;
	}
}

public class CatTest {
	public static void main(String[] args) {
		for ( int i = 0 ; i < 10 ; i ++ ) 
			Cat cat = new Cat();
		System.out.println(Cat.getInstance());
	}
}
       上面程式試圖通過for迴圈來建立10個Cat物件,然後通過getInstance()靜態方法獲取instance的值,由於迴圈體只有一條語句,因此省略了迴圈體的花括號,但是如果嘗試編譯該程式,編譯器會報錯:Syntax error, insert ";" to complete Statement。發生這種錯誤的原因: 因為Java語言規定:for、while或do迴圈中的重複執行語句不能是一條單獨的區域性變數定義語句;如果程式要使用迴圈來重複定義區域性變數,這條區域性變數定義語句必須放在花括號內才有效。因此將程式改為如下所示。
class Cat {
	private static long instance = 0;
	
	public Cat() {
		System.out.println("執行無引數的構造器");
		instance++;
	}
	
	public static long getInstance() {
		return instance;
	}
}

public class CatTest {
	public static void main(String[] args) {
		for ( int i = 0 ; i < 10 ; i ++ ) {
			Cat cat = new Cat();
		}
		System.out.println(Cat.getInstance());
	}
}