Java支持簡單語句和復(fù)合語句。比如賦值和子函數(shù)調(diào)用這樣的簡單語句是構(gòu)建程序的基礎(chǔ)模塊。像while循環(huán)和if語句這樣的復(fù)合語句用來將簡單語句組織成復(fù)雜的結(jié)構(gòu)。這種結(jié)構(gòu)被稱作控制結(jié)構(gòu),用來控制語句的執(zhí)行順序。下面的五個章節(jié)會討論Java中的控制結(jié)構(gòu),從本節(jié)的while語句和do…while語句開始介紹。與此同時,我們會給出每種控制結(jié)構(gòu)的示例程序并將其應(yīng)用到前一節(jié)算法設(shè)計例子中。 3.3.1 while循環(huán)在之前的3.1節(jié)中已經(jīng)介紹了while循環(huán),結(jié)構(gòu)如下:
while語句是一個代碼塊,由一組語句組合在一起并包含在一對括號中。結(jié)構(gòu)中的statement被稱作循環(huán)體。當(dāng)boolean-expression為true時,會循環(huán)執(zhí)行循環(huán)體中的語句。這個布爾表達(dá)式被稱作循環(huán)條件,執(zhí)行簡單的測試。有幾點需要澄清。在循環(huán)體一次都沒有執(zhí)行前,循環(huán)條件為false時會發(fā)生什么?這種情況下,循環(huán)體永遠(yuǎn)不會執(zhí)行。while循環(huán)的主體可能會任性任意多次,當(dāng)然也可能是0次。當(dāng)執(zhí)行到循環(huán)體中間某條語句時循環(huán)條件由true變?yōu)閒alse時會怎么樣?會馬上結(jié)束循環(huán)嗎?不會,因為計算機(jī)會一直執(zhí)行到循環(huán)結(jié)束為止。只有當(dāng)重新跳轉(zhuǎn)到循環(huán)開始并且測試循環(huán)條件時,循環(huán)才會結(jié)束。 讓我們來看看使用while循環(huán)解決問題的一個典型示例:用戶輸入一組正整數(shù),算出它們的平均值。平均值的算法,是所有整數(shù)的和除以整數(shù)個數(shù)。程序會要求用戶每次輸入一個整數(shù),記錄輸入整數(shù)的個數(shù),然后計算所有已錄入數(shù)字的和。下面是這段程序的偽代碼:
如何知道還有待輸入的整數(shù)呢?一種典型的解決方法是,讓用戶在所有數(shù)據(jù)錄入完畢時輸入0。這種方法在所有數(shù)據(jù)都是正整數(shù)的情況下有效,這時0不是一個合法的數(shù)值。0本身不作為計算平均數(shù)集合中的數(shù)據(jù),僅僅作為真實數(shù)據(jù)錄入結(jié)束的標(biāo)志。這種方法一些場合下被稱為使用哨兵值。所以,現(xiàn)在while循環(huán)的測試條件變?yōu)椤爱?dāng)輸入的整數(shù)非0”。但是這里有另外一個問題!第一次判斷循環(huán)條件時,循環(huán)體尚未執(zhí)行,這時還沒有讀取任何數(shù)值。也就是說,還沒有“輸入的整數(shù)”。這時判斷輸入整數(shù)是否為0是沒有意義的。因此,我們需要在循環(huán)執(zhí)行前做一些處理,把必要的信息準(zhǔn)備好。這里,我們只要在循環(huán)的前面讀取第一個整數(shù)就可以了。下面是修改后的算法:
請注意,這里我重新調(diào)整了循環(huán)體。由于在循環(huán)開始前就讀取了整數(shù),在循環(huán)一開始就需要處理讀到的整數(shù)。在循環(huán)的最后,計算機(jī)會讀取一個新的整數(shù)。計算機(jī)會跳轉(zhuǎn)到循環(huán)開始的地方,用新讀取的值測試循環(huán)條件。注意:當(dāng)計算機(jī)讀取最后的哨兵值以后,會直接結(jié)束循環(huán)而不對其進(jìn)行處理。既不會累計到sum中,也不會算到count里。這就是算法的工作機(jī)制。哨兵值不作為數(shù)據(jù)的一部分。在最初的算法中,不做循環(huán)前的準(zhǔn)備會累計所有的值包括哨兵值,所以結(jié)果是錯的。(哨兵值為0,因此sum的結(jié)果是正確的,但是count會多算了1個。這種常見的錯誤被稱作“差一錯誤”。循環(huán)中進(jìn)行計數(shù)會比看上去難得多?。?/p> 可以很容易地把算法轉(zhuǎn)換成一個完整的程序。注意,在程序中不能用“average = sum/count;”這樣的語句計算平均值。因為sum和count都是int類型,sum/count的結(jié)果是整數(shù),而平均值應(yīng)該是實數(shù)。我們之前已經(jīng)遇到過了這個問題:把其中一個int值轉(zhuǎn)換為double類型,強(qiáng)制計算機(jī)把商值作為實數(shù)計算。具體的做法,將其中一個變量強(qiáng)制類型轉(zhuǎn)換為double?!?double)sum”將sum值轉(zhuǎn)為實數(shù),因此計算平均數(shù)可以改成“average = ((double)sum) / count;”。還有一種方法,把聲明變量時就聲明為double類型。 程序還存在另一個問題:用戶一開始輸入0時,程序不會再處理其它輸入。這種用例可以來測試循環(huán)結(jié)束時count是否還等于0??雌饋磉@是細(xì)節(jié)問題,但是仔細(xì)的程序員應(yīng)該考慮所有的情況。 下面是程序的完整代碼:
3.3.2 do..while語句有時候,在循環(huán)結(jié)尾測試循環(huán)條件會比像while循環(huán)那樣開頭判斷更加方便。do..while語句與while循環(huán)非常類似,區(qū)別在于“while”及循環(huán)體被移到了結(jié)尾,在循環(huán)的開頭添加了“do”。do..while語句的結(jié)構(gòu)如下:
通常情況下,statement可能是一個代碼塊:
注意:在do..while的結(jié)尾有一個分號“;”。這個分號也是語句的一部分,與賦值語句或聲明語句結(jié)尾的分號一樣。漏寫分號會造成語法錯誤。(通常,每個Java語句都會以分號或右花括號“}”結(jié)尾) 執(zhí)行do循環(huán)時,計算機(jī)會首先執(zhí)行循環(huán)體中的語句,然后判斷循環(huán)條件。如果循環(huán)條件表達(dá)式為true,計算機(jī)會回到do循環(huán)開頭繼續(xù)執(zhí)行;如果為false,計算機(jī)會終止循環(huán)繼續(xù)執(zhí)行程序的其它部分。由于只有在循環(huán)末尾才會進(jìn)行條件判斷,do循環(huán)至少會執(zhí)行一次循環(huán)體。 例如,下面的偽代碼是一個游戲程序。使用do循環(huán)比起while循環(huán)更有意義,至少能玩一盤游戲。程序的開始版本,循環(huán)判斷條件沒有意義:
把上面的偽代碼轉(zhuǎn)成Java。開始不去討論游戲的細(xì)節(jié),讓我們定義一個Checkers類,其中包含了一個static成員函數(shù)叫做playGame(),和程序的使用者玩跳棋游戲。偽代碼“玩一盤游戲”被轉(zhuǎn)換為調(diào)用“Checkers.playGame();”。我們需要一個變量存儲用戶的反饋。TextIO類通過一個boolean變量存儲 yes/no 的回復(fù)結(jié)果。“Yes”表示true,“no”表示false。因此算法的代碼會變成:
當(dāng)boolean變量的值變?yōu)閒alse,表示循環(huán)應(yīng)當(dāng)結(jié)束。在程序的一個地方賦值,在另一個地方作為判斷條件——當(dāng)boolean變量這樣使用時,被稱為標(biāo)志(flag)或標(biāo)志變量(表示信號標(biāo)志)。 順便說一下,程序員通常會鄙視這樣的寫法“while (wantsToContinue == true)”。這種方式過于教條,可以用“while (wantsToContinue)”代表同樣的含義。類似的,還有“flag == false”這樣的寫法,flag是一個boolean變量。“flag == false”與“!flag”完全等價,這里的感嘆號!表示對boolean值進(jìn)行取反操作。所以,可以用“while (!flag)”取代“while (flag == false)”,用“if (!flag)”取代“if (flag == false)”。 盡管do..while語句有時候比while語句更加方便,但是兩種循環(huán)并沒有讓語言更強(qiáng)大。任何可以用do..while循環(huán)解決的問題都可以用while完成,反之亦然。事實上doSomething可以代碼任何一個代碼塊:
與下面的代碼功能一致:
類似的,
可以替換為:
程序的功能沒有任何變化。 3.3.3 break和continue語句while循環(huán)與do..while循環(huán)會在程序的開始或結(jié)尾測試循環(huán)條件。有時候,在循環(huán)體中間或者幾個不同的地方測試條件會更加合理。Java提供了在循環(huán)體中跳出循環(huán)的通用方法,叫做break語句,形式如下:
當(dāng)計算機(jī)在循環(huán)體重執(zhí)行break語句時,會立刻跳出循環(huán)。接下來會繼續(xù)執(zhí)行循環(huán)后面的語句??紤]下面的示例:
如果用戶輸入的數(shù)值大于0,會執(zhí)行break語句跳出循環(huán)。否則,計算機(jī)會輸出“Your answer must be > 0.”然后跳轉(zhuǎn)到循環(huán)的開頭繼續(xù)讀取其它用戶輸入的值。 循環(huán)的第一行,“while (true)”可能會有一點奇怪,但確是合法的。while循環(huán)的條件可以是任意boolean類型的表達(dá)式。計算機(jī)會判斷檢查式的值看是true還是false。boolean值“true”也是一個boolean表達(dá)式,值為true。所以,“while (true)”表示無限循環(huán),可以通過break語句終止無限循環(huán)。 break語句會立刻終止包含了該語句的循環(huán)。Java支持循環(huán)嵌套,即一個循環(huán)中包含另一個循環(huán)。如果在嵌套的循環(huán)內(nèi)調(diào)用break語句,只會跳出該層循環(huán),而非跳出外層循環(huán)。還有一種跳轉(zhuǎn)叫做標(biāo)簽中斷(labeled break),可以指定希望跳出的循環(huán)。這種用法并不常見,這里我會快速帶過。標(biāo)簽(Label)的工作方式如下:可以在任何循環(huán)前面加上標(biāo)簽。標(biāo)簽由一個簡單標(biāo)識符帶一個冒號組成。例如,帶label的while循環(huán)看起來像這樣“mainloop: while…”,在循環(huán)內(nèi)部,你可以使用帶標(biāo)簽的跳轉(zhuǎn)語句,比如“break mainloop;”來跳轉(zhuǎn)帶標(biāo)簽的循環(huán)。例如,下面這段代碼檢查兩個字符串,s1和s2,有一個共同的字符。如果找到共同字符,標(biāo)志變量nothingInCommon會置為false,通過標(biāo)簽中斷結(jié)束處理:
continue語句與break類似,但是很少使用。continue語句告訴計算機(jī)跳過本次循環(huán)剩余語句的執(zhí)行。然而,與跳出循環(huán)不同,continue會跳轉(zhuǎn)到循環(huán)開始繼續(xù)下一次迭代(包括判斷循環(huán)變量的值是否需要繼續(xù)迭代)。與break語句類似,在嵌套循環(huán)中執(zhí)行continue語句時,會直接轉(zhuǎn)到包含該語句的循環(huán)開始;“標(biāo)簽繼續(xù)(labeled continue)“會轉(zhuǎn)到指定的循環(huán)繼續(xù)執(zhí)行。 break和continue語句可以用在while循環(huán)與do..while循環(huán)中。它們也可以在接下來的章節(jié)中介紹的循環(huán)中使用。在3.6節(jié),我們會看到在switch語句中使用break。break還可以在if語句中使用,前提是if語句嵌套在循環(huán)火種switch語句中。在這種情況下,break并不意味著會跳出if語句,而是跳出包含著if語句的循環(huán)或switch語句。在if語句中使用continue也是類似的用法。 |
|
來自: yy99k > 《java編程入門》