<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # 3.2 執行控制 (3)2 執行控制 Java使用了C的全部控制語句,所以假期您以前用C或C++編程,其中大多數都應是非常熟悉的。大多數程序化的編程語言都提供了某種形式的控制語句,這在語言間通常是共通的。在Java里,涉及的關鍵字包括`if-else`、`while`、`do-while`、`for`以及一個名為`switch`的選擇語句。然而,Java并不支持非常有害的`goto`(它仍是解決某些特殊問題的權宜之計)。仍然可以進行象`goto`那樣的跳轉,但比典型的`goto`要局限多了。 ## 3.2.1 真和假 所有條件語句都利用條件表達式的真或假來決定執行流程。條件表達式的一個例子是`A==B`。它用條件運算符`==`來判斷`A`值是否等于`B`值。該表達式返回`true`或`false`。本章早些時候接觸到的所有關系運算符都可拿來構造一個條件語句。注意Java不允許我們將一個數字作為布爾值使用,即使它在C和C++里是允許的(真是非零,而假是零)。若想在一次布爾測試中使用一個非布爾值——比如在`if(a)`里,那么首先必須用一個條件表達式將其轉換成一個布爾值,例如`if(a!=0)`。 ## 3.2.2 `if-else` `if-else`語句或許是控制程序流程最基本的形式。其中的`else`是可選的,所以可按下述兩種形式來使用`if`: ``` if(布爾表達式) 語句 ``` 或者 ``` if(布爾表達式) 語句 else 語句 ``` 條件必須產生一個布爾結果。“語句”要么是用分號結尾的一個簡單語句,要么是一個復合語句——封閉在括號內的一組簡單語句。在本書任何地方,只要提及“語句”這個詞,就有可能包括簡單或復合語句。 作為`if-else`的一個例子,下面這個`test()`方法可告訴我們猜測的一個數字位于目標數字之上、之下還是相等: ``` static int test(int testval) { int result = 0; if(testval > target) result = -1; else if(testval < target) result = +1; else result = 0; // match return result; } ``` 最好將流程控制語句縮進排列,使讀者能方便地看出起點與終點。 (1) `return` `return`關鍵字有兩方面的用途:指定一個方法返回什么值(假設它沒有`void`返回值),并立即返回那個值。可據此改寫上面的`test()`方法,使其利用這些特點: ``` static int test2(int testval) { if(testval > target) return -1; if(testval < target) return +1; return 0; // match } ``` 不必加上`else`,因為方法在遇到`return`后便不再繼續。 ## 3.2.3 迭代 `while`,`do-while`和`for`控制著循環,有時將其劃分為“迭代語句”。除非用于控制迭代的布爾表達式得到“假”的結果,否則語句會重復執行下去。`while`循環的格式如下: ``` while(布爾表達式) 語句 ``` 在循環剛開始時,會計算一次“布爾表達式”的值。而對于后來每一次額外的循環,都會在開始前重新計算一次。 下面這個簡單的例子可產生隨機數,直到符合特定的條件為止: ``` //: WhileTest.java // Demonstrates the while loop public class WhileTest { public static void main(String[] args) { double r = 0; while(r < 0.99d) { r = Math.random(); System.out.println(r); } } } ///:~ ``` 它用到了`Math`庫里的`static`(靜態)方法`random()`。該方法的作用是產生0和1之間(包括0,但不包括1)的一個`double`值。`while`的條件表達式意思是說:“一直循環下去,直到數字等于或大于0.99”。由于它的隨機性,每運行一次這個程序,都會獲得大小不同的數字列表。 ## 3.2.4 `do-while` `do-while`的格式如下: ``` do 語句 while(布爾表達式) ``` `while`和`do-while`唯一的區別就是`do-while`肯定會至少執行一次;也就是說,至少會將其中的語句“過一遍”——即便表達式第一次便計算為`false`。而在`while`循環結構中,若條件第一次就為`false`,那么其中的語句根本不會執行。在實際應用中,`while`比`do-while`更常用一些。 ## 3.2.5 `for` `for`循環在第一次迭代之前要進行初始化。隨后,它會進行條件測試,而且在每一次迭代的時候,進行某種形式的“步進”(Stepping)。`for`循環的形式如下: ``` for(初始表達式; 布爾表達式; 步進) 語句 ``` 無論初始表達式,布爾表達式,還是步進,都可以置空。每次迭代前,都要測試一下布爾表達式。若獲得的結果是`false`,就會繼續執行緊跟在`for`語句后面的那行代碼。在每次循環的末尾,會計算一次步進。 `for`循環通常用于執行“計數”任務: ``` //: ListCharacters.java // Demonstrates "for" loop by listing // all the ASCII characters. public class ListCharacters { public static void main(String[] args) { for( char c = 0; c < 128; c++) if (c != 26 ) // ANSI Clear screen System.out.println( "value: " + (int)c + " character: " + c); } } ///:~ ``` 注意變量`c`是在需要用到它的時候定義的——在`for`循環的控制表達式內部,而非在由起始花括號標記的代碼塊的最開頭。`c`的作用域是由`for`控制的表達式。 以于象C這樣傳統的程序化語言,要求所有變量都在一個塊的開頭定義。所以在編譯器創建一個塊的時候,它可以為那些變量分配空間。而在Java和C++中,則可在整個塊的范圍內分散變量聲明,在真正需要的地方才加以定義。這樣便可形成更自然的編碼風格,也更易理解。 可在`for`語句里定義多個變量,但它們必須具有同樣的類型: ``` for(int i = 0, j = 1; i < 10 && j != 11; i++, j++) /* body of for loop */; ``` 其中,`for`語句內的`int`定義同時覆蓋了`i`和`j`。只有`for`循環才具備在控制表達式里定義變量的能力。對于其他任何條件或循環語句,都不可采用這種方法。 (1) 逗號運算符 早在第1章,我們已提到了逗號運算符——注意不是逗號分隔符;后者用于分隔函數的不同參數。Java里唯一用到逗號運算符的地方就是`for`循環的控制表達式。在控制表達式的初始化和步進控制部分,我們可使用一系列由逗號分隔的語句。而且那些語句均會獨立執行。前面的例子已運用了這種能力,下面則是另一個例子: ``` //: CommaOperator.java public class CommaOperator { public static void main(String[] args) { for(int i = 1, j = i + 10; i < 5; i++, j = i * 2) { System.out.println("i= " + i + " j= " + j); } } } ///:~ ``` 輸出如下: ``` i= 1 j= 11 i= 2 j= 4 i= 3 j= 6 i= 4 j= 8 ``` 大家可以看到,無論在初始化還是在步進部分,語句都是順序執行的。此外,盡管初始化部分可設置任意數量的定義,但都屬于同一類型。 ## 3.2.6 中斷和繼續 在任何循環語句的主體部分,亦可用`break`和`continue`控制循環的流程。其中,`break`用于強行退出循環,不執行循環中剩余的語句。而`continue`則停止執行當前的迭代,然后退回循環起始和,開始新的迭代。 下面這個程序向大家展示了`break`和`continue`在`for`和`while`循環中的例子: ``` //: BreakAndContinue.java // Demonstrates break and continue keywords public class BreakAndContinue { public static void main(String[] args) { for(int i = 0; i < 100; i++) { if(i == 74) break; // Out of for loop if(i % 9 != 0) continue; // Next iteration System.out.println(i); } int i = 0; // An "infinite loop": while(true) { i++; int j = i * 27; if(j == 1269) break; // Out of loop if(i % 10 != 0) continue; // Top of loop System.out.println(i); } } } ///:~ ``` 在這個`for`循環中,`i`的值永遠不會到達100。因為一旦`i`到達74,`break`語句就會中斷循環。通常,只有在不知道中斷條件何時滿足時,才需象這樣使用`break`。只要`i`不能被9整除,`continue`語句會使程序流程返回循環的最開頭執行(所以使`i`值遞增)。如果能夠整除,則將值顯示出來。 第二部分向大家揭示了一個“無限循環”的情況。然而,循環內部有一個`break`語句,可中止循環。除此以外,大家還會看到`continue`移回循環頂部,同時不完成剩余的內容(所以只有在i值能被9整除時才打印出值)。輸出結果如下: ``` 0 9 18 27 36 45 54 63 72 10 20 30 40 ``` 之所以顯示0,是由于`0%9`等于0。 無限循環的第二種形式是`for(;;)`。編譯器將`while(true)`與`for(;;)`看作同一回事。所以具體選用哪個取決于自己的編程習慣。 (1) 臭名昭著的`goto` `goto`關鍵字很早就在程序設計語言中出現。事實上,`goto`是匯編語言的程序控制結構的始祖:“若條件`A`,則跳到這里;否則跳到那里”。若閱讀由幾乎所有編譯器生成的匯編代碼,就會發現程序控制里包含了許多跳轉。然而,`goto`是在源碼的級別跳轉的,所以招致了不好的聲譽。若程序總是從一個地方跳到另一個地方,還有什么辦法能識別代碼的流程呢?隨著Edsger Dijkstra著名的“Goto有害”論的問世,`goto`便從此失寵。 事實上,真正的問題并不在于使用`goto`,而在于`goto`的濫用。而且在一些少見的情況下,`goto`是組織控制流程的最佳手段。 盡管`goto`仍是Java的一個保留字,但并未在語言中得到正式使用;Java沒有`goto`。然而,在`break`和`continue`這兩個關鍵字的身上,我們仍然能看出一些`goto`的影子。它并不屬于一次跳轉,而是中斷循環語句的一種方法。之所以把它們納入`goto`問題中一起討論,是由于它們使用了相同的機制:標簽。 “標簽”是后面跟一個冒號的標識符,就象下面這樣: ``` label1: ``` 對Java來說,唯一用到標簽的地方是在循環語句之前。進一步說,它實際需要緊靠在循環語句的前方——在標簽和循環之間置入任何語句都是不明智的。而在循環之前設置標簽的唯一理由是:我們希望在其中嵌套另一個循環或者一個開關。這是由于`break`和`continue`關鍵字通常只中斷當前循環,但若隨同標簽使用,它們就會中斷到存在標簽的地方。如下所示: ``` label1: 外部循環{ 內部循環{ //... break; //1 //... continue; //2 //... continue label1; //3 //... break label1; //4 } } ``` 在條件1中,`break`中斷內部循環,并在外部循環結束。在條件2中,`continue`移回內部循環的起始處。但在條件3中,`continue label1`卻同時中斷內部循環以及外部循環,并移至`label1`處。隨后,它實際是繼續循環,但卻從外部循環開始。在條件4中,break label1也會中斷所有循環,并回到label1處,但并不重新進入循環。也就是說,它實際是完全中止了兩個循環。 下面是`for`循環的一個例子: ``` //: LabeledFor.java // Java’s "labeled for loop" public class LabeledFor { public static void main(String[] args) { int i = 0; outer: // Can't have statements here for(; true ;) { // infinite loop inner: // Can't have statements here for(; i < 10; i++) { prt("i = " + i); if(i == 2) { prt("continue"); continue; } if(i == 3) { prt("break"); i++; // Otherwise i never // gets incremented. break; } if(i == 7) { prt("continue outer"); i++; // Otherwise i never // gets incremented. continue outer; } if(i == 8) { prt("break outer"); break outer; } for(int k = 0; k < 5; k++) { if(k == 3) { prt("continue inner"); continue inner; } } } } // Can't break or continue // to labels here } static void prt(String s) { System.out.println(s); } } ///:~ ``` 這里用到了在其他例子中已經定義的`prt()`方法。 注意`break`會中斷`for`循環,而且在抵達`for`循環的末尾之前,遞增表達式不會執行。由于`break`跳過了遞增表達式,所以遞增會在`i==3`的情況下直接執行。在`i==7`的情況下,`continue outer`語句也會到達循環頂部,而且也會跳過遞增,所以它也是直接遞增的。 下面是輸出結果: ``` i = 0 continue inner i = 1 continue inner i = 2 continue i = 3 break i = 4 continue inner i = 5 continue inner i = 6 continue inner i = 7 continue outer i = 8 break outer ``` 如果沒有`break outer`語句,就沒有辦法在一個內部循環里找到出外部循環的路徑。這是由于break本身只能中斷最內層的循環(對于`continue`同樣如此)。 當然,若想在中斷循環的同時退出方法,簡單地用一個`return`即可。 下面這個例子向大家展示了帶標簽的`break`以及`continue`語句在`while`循環中的用法: ``` //: LabeledWhile.java // Java's "labeled while" loop public class LabeledWhile { public static void main(String[] args) { int i = 0; outer: while(true) { prt("Outer while loop"); while(true) { i++; prt("i = " + i); if(i == 1) { prt("continue"); continue; } if(i == 3) { prt("continue outer"); continue outer; } if(i == 5) { prt("break"); break; } if(i == 7) { prt("break outer"); break outer; } } } } static void prt(String s) { System.out.println(s); } } ///:~ ``` 同樣的規則亦適用于`while`: (1) 簡單的一個`continue`會退回最內層循環的開頭(頂部),并繼續執行。 (2) 帶有標簽的`continue`會到達標簽的位置,并重新進入緊接在那個標簽后面的循環。 (3) `break`會中斷當前循環,并移離當前標簽的末尾。 (4) 帶標簽的`break`會中斷當前循環,并移離由那個標簽指示的循環的末尾。 這個方法的輸出結果是一目了然的: ``` Outer while loop i = 1 continue i = 2 i = 3 continue outer Outer while loop i = 4 i = 5 break Outer while loop i = 6 i = 7 break outer ``` 大家要記住的重點是:在Java里唯一需要用到標簽的地方就是擁有嵌套循環,而且想中斷或繼續多個嵌套級別的時候。 在Dijkstra的“Goto有害”論中,他最反對的就是標簽,而非`goto`。隨著標簽在一個程序里數量的增多,他發現產生錯誤的機會也越來越多。標簽和`goto`使我們難于對程序作靜態分析。這是由于它們在程序的執行流程中引入了許多“怪圈”。但幸運的是,Java標簽不會造成這方面的問題,因為它們的活動場所已被限死,不可通過特別的方式到處傳遞程序的控制權。由此也引出了一個有趣的問題:通過限制語句的能力,反而能使一項語言特性更加有用。 ## 3.2.7 開關 “開關”(`Switch`)有時也被劃分為一種“選擇語句”。根據一個整數表達式的值,`switch`語句可從一系列代碼選出一段執行。它的格式如下: ``` switch(整數選擇因子) { case 整數值1 : 語句; break; case 整數值2 : 語句; break; case 整數值3 : 語句; break; case 整數值4 : 語句; break; case 整數值5 : 語句; break; //.. default:語句; } ``` 其中,“整數選擇因子”是一個特殊的表達式,能產生整數值。`switch`能將整數選擇因子的結果與每個整數值比較。若發現相符的,就執行對應的語句(簡單或復合語句)。若沒有發現相符的,就執行`default`語句。 在上面的定義中,大家會注意到每個`case`均以一個`break`結尾。這樣可使執行流程跳轉至`switch`主體的末尾。這是構建`switch`語句的一種傳統方式,但`break`是可選的。若省略`break`,會繼續執行后面的`case`語句的代碼,直到遇到一個`break`為止。盡管通常不想出現這種情況,但對有經驗的程序員來說,也許能夠善加利用。注意最后的`default`語句沒有`break`,因為執行流程已到了`break`的跳轉目的地。當然,如果考慮到編程風格方面的原因,完全可以在`default`語句的末尾放置一個`break`,盡管它并沒有任何實際的用處。 `switch`語句是實現多路選擇的一種易行方式(比如從一系列執行路徑中挑選一個)。但它要求使用一個選擇因子,并且必須是`int`或`char`那樣的整數值。例如,假若將一個字符串或者浮點數作為選擇因子使用,那么它們在`switch`語句里是不會工作的。對于非整數類型,則必須使用一系列`if`語句。 下面這個例子可隨機生成字母,并判斷它們是元音還是輔音字母: ``` //: VowelsAndConsonants.java // Demonstrates the switch statement public class VowelsAndConsonants { public static void main(String[] args) { for(int i = 0; i < 100; i++) { char c = (char)(Math.random() * 26 + 'a'); System.out.print(c + ": "); switch(c) { case 'a': case 'e': case 'i': case 'o': case 'u': System.out.println("vowel"); break; case 'y': case 'w': System.out.println( "Sometimes a vowel"); break; default: System.out.println("consonant"); } } } } ///:~ ``` 由于`Math.random()`會產生0到1之間的一個值,所以只需將其乘以想獲得的最大隨機數(對于英語字母,這個數字是26),再加上一個偏移量,得到最小的隨機數。 盡管我們在這兒表面上要處理的是字符,但`switch`語句實際使用的字符的整數值。在`case`語句中,用單引號封閉起來的字符也會產生整數值,以便我們進行比較。 請注意`case`語句相互間是如何聚合在一起的,它們依次排列,為一部分特定的代碼提供了多種匹配模式。也應注意將`break`語句置于一個特定`case`的末尾,否則控制流程會簡單地下移,并繼續判斷下一個條件是否相符。 (1) 具體的計算 應特別留意下面這個語句: ``` char c = (char)(Math.random() * 26 + 'a'); ``` `Math.random()`會產生一個`double`值,所以26會轉換成`double`類型,以便執行乘法運算。這個運算也會產生一個`double`值。這意味著為了執行加法,必須無將`'a'`轉換成一個`double`。利用一個“轉換”,`double`結果會轉換回`char`。 我們的第一個問題是,轉換會對`char`作什么樣的處理呢?換言之,假設一個值是29.7,我們把它轉換成一個`char`,那么結果值到底是30還是29呢?答案可從下面這個例子中得到: ``` //: CastingNumbers.java // What happens when you cast a float or double // to an integral value? public class CastingNumbers { public static void main(String[] args) { double above = 0.7, below = 0.4; System.out.println("above: " + above); System.out.println("below: " + below); System.out.println( "(int)above: " + (int)above); System.out.println( "(int)below: " + (int)below); System.out.println( "(char)('a' + above): " + (char)('a' + above)); System.out.println( "(char)('a' + below): " + (char)('a' + below)); } } ///:~ ``` 輸出結果如下: ``` above: 0.7 below: 0.4 (int)above: 0 (int)below: 0 (char)('a' + above): a (char)('a' + below): a ``` 所以答案就是:將一個`float`或`double`值轉換成整數值后,總是將小數部分“砍掉”,不作任何進位處理。 第二個問題與`Math.random()`有關。它會產生0和1之間的值,但是否包括值1呢?用正統的數學語言表達,它到底是`(0,1)`,`[0,1]`,`(0,1]`,還是`[0,1)`呢(方括號表示“包括”,圓括號表示“不包括”)?同樣地,一個示范程序向我們揭示了答案: ``` //: RandomBounds.java // Does Math.random() produce 0.0 and 1.0? public class RandomBounds { static void usage() { System.err.println("Usage: \n\t" + "RandomBounds lower\n\t" + "RandomBounds upper"); System.exit(1); } public static void main(String[] args) { if(args.length != 1) usage(); if(args[0].equals("lower")) { while(Math.random() != 0.0) ; // Keep trying System.out.println("Produced 0.0!"); } else if(args[0].equals("upper")) { while(Math.random() != 1.0) ; // Keep trying System.out.println("Produced 1.0!"); } else usage(); } } ///:~ ``` 為運行這個程序,只需在命令行鍵入下述命令即可: ``` java RandomBounds lower ``` 或 ``` java RandomBounds upper ``` 在這兩種情況下,我們都必須人工中斷程序,所以會發現`Math.random()`“似乎”永遠都不會產生0.0或1.0。但這只是一項實驗而已。若想到0和1之間有2的128次方不同的雙精度小數,所以如果全部產生這些數字,花費的時間會遠遠超過一個人的生命。當然,最后的結果是在`Math.random()`的輸出中包括了0.0。或者用數字語言表達,輸出值范圍是`[0,1)`。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看