Java™ 教程(控制流語句)

博弈發表於2019-01-19

控制流語句

原始檔中的語句通常按照它們出現的順序從上到下執行,但是,控制流語句通過使用決策、迴圈和分支來分解執行流程,使你的程式能夠有條件地執行特定的程式碼塊,本節描述Java程式語言支援的決策語句(if-thenif-then-elseswitch),迴圈語句(forwhiledo-while)以及分支語句(breakcontinuereturn)。

if-then和if-then-else語句

if-then語句

if-then語句是所有控制流語句中最基本的語句,它告訴程式只有在特定測試評估為true時才執行某段程式碼,例如,Bicycle類可以允許制動器僅在自行車已經運動時降低自行車的速度,applyBrakes方法的一種可能實現如下:

void applyBrakes() {
    // the "if" clause: bicycle must be moving
    if (isMoving){ 
        // the "then" clause: decrease current speed
        currentSpeed--;
    }
}

如果此測試評估為false(意味著自行車不運動),則控制跳轉到if-then語句的末尾。

此外,只要“then”子句只包含一個語句,開括號和結束括號是可選的:

void applyBrakes() {
    // same as above, but without braces 
    if (isMoving)
        currentSpeed--;
}

決定何時省略括號是個人品味的問題,省略它們會使程式碼變得更脆弱,如果稍後將第二個語句新增到“then”子句中,則常見的錯誤是忘記新增新所需的花括號,編譯器無法捕獲這種錯誤,你會得到錯誤的結果。

if-then-else語句

if-then-else語句在“if”子句求值為false時提供輔助執行路徑,如果在自行車不運動時應用制動器,你可以在applyBrakes方法中使用if-then-else語句來執行某些操作,在這種情況下,操作是簡單地列印一條錯誤訊息,指出自行車已經停止。

void applyBrakes() {
    if (isMoving) {
        currentSpeed--;
    } else {
        System.err.println("The bicycle has already stopped!");
    } 
}

以下程式IfElseDemo根據測試分數的值分配成績:A得分為90%或以上,B得分為80%或以上,依此類推。

class IfElseDemo {
    public static void main(String[] args) {

        int testscore = 76;
        char grade;

        if (testscore >= 90) {
            grade = `A`;
        } else if (testscore >= 80) {
            grade = `B`;
        } else if (testscore >= 70) {
            grade = `C`;
        } else if (testscore >= 60) {
            grade = `D`;
        } else {
            grade = `F`;
        }
        System.out.println("Grade = " + grade);
    }
}

該程式的輸出是:

Grade = C

你可能已經注意到testscore的值可以滿足複合語句中的多個表示式:76 >= 7076 >= 60,但是,一旦滿足條件,就會執行適當的語句(grade =`C`;),並且不評估其餘條件。

switch語句

if-thenif-then-else語句不同,switch語句可以有許多可能的執行路徑,switch使用byteshortcharint原始資料型別,它還適用於列舉型別(在列舉型別中討論),String類,以及一些包含某些基本型別的特殊類:CharacterByteShortInteger(在NumberString中討論)。

以下程式碼示例SwitchDemo宣告瞭一個名為monthint,其值表示月份,程式碼使用switch語句根據month的值顯示月份的名稱。

public class SwitchDemo {
    public static void main(String[] args) {

        int month = 8;
        String monthString;
        switch (month) {
            case 1:  monthString = "January";
                     break;
            case 2:  monthString = "February";
                     break;
            case 3:  monthString = "March";
                     break;
            case 4:  monthString = "April";
                     break;
            case 5:  monthString = "May";
                     break;
            case 6:  monthString = "June";
                     break;
            case 7:  monthString = "July";
                     break;
            case 8:  monthString = "August";
                     break;
            case 9:  monthString = "September";
                     break;
            case 10: monthString = "October";
                     break;
            case 11: monthString = "November";
                     break;
            case 12: monthString = "December";
                     break;
            default: monthString = "Invalid month";
                     break;
        }
        System.out.println(monthString);
    }
}

在這種情況下,August列印到標準輸出。

switch語句的主體稱為switch塊,可以使用一個或多個case或預設標籤來標記switch塊中的語句,switch語句計算其表示式,然後執行匹配的case標籤後面的所有語句。

你還可以使用if-then-else語句顯示月份的名稱:

int month = 8;
if (month == 1) {
    System.out.println("January");
} else if (month == 2) {
    System.out.println("February");
}
...  // and so on

決定是否使用if-then-else語句或switch語句是基於可讀性和語句正在測試的表示式,if-then-else語句可以基於值或條件的範圍來測試表示式,而switch語句僅基於單個整數、列舉值或String物件來測試表示式。

另一個興趣點是break語句,每個break語句都會終止封閉的switch語句。控制流繼續switch塊後面的第一個語句,break語句是必要的,因為沒有它們,switch塊中的語句就會失敗:匹配的case標籤之後的所有語句都按順序執行,而不管後續case標籤的表示式,直到遇到break語句。程式SwitchDemoFallThrough顯示落入所有switch塊中的語句,該程式顯示與整數月相對應的月份以及該年份中的月份:

public class SwitchDemoFallThrough {

    public static void main(String[] args) {
        java.util.ArrayList<String> futureMonths =
            new java.util.ArrayList<String>();

        int month = 8;

        switch (month) {
            case 1:  futureMonths.add("January");
            case 2:  futureMonths.add("February");
            case 3:  futureMonths.add("March");
            case 4:  futureMonths.add("April");
            case 5:  futureMonths.add("May");
            case 6:  futureMonths.add("June");
            case 7:  futureMonths.add("July");
            case 8:  futureMonths.add("August");
            case 9:  futureMonths.add("September");
            case 10: futureMonths.add("October");
            case 11: futureMonths.add("November");
            case 12: futureMonths.add("December");
                     break;
            default: break;
        }

        if (futureMonths.isEmpty()) {
            System.out.println("Invalid month number");
        } else {
            for (String monthName : futureMonths) {
               System.out.println(monthName);
            }
        }
    }
}

這是程式碼的輸出:

August
September
October
November
December

從技術上講,不需要最後的break,因為流從switch語句中退出,建議使用break,以便更容易修改程式碼並減少錯誤,預設部分處理其中一個case部分未明確處理的所有值。

以下程式碼示例SwitchDemo2顯示了語句如何具有多個case標籤,程式碼示例計算特定月份的天數:

class SwitchDemo2 {
    public static void main(String[] args) {

        int month = 2;
        int year = 2000;
        int numDays = 0;

        switch (month) {
            case 1: case 3: case 5:
            case 7: case 8: case 10:
            case 12:
                numDays = 31;
                break;
            case 4: case 6:
            case 9: case 11:
                numDays = 30;
                break;
            case 2:
                if (((year % 4 == 0) && 
                     !(year % 100 == 0))
                     || (year % 400 == 0))
                    numDays = 29;
                else
                    numDays = 28;
                break;
            default:
                System.out.println("Invalid month.");
                break;
        }
        System.out.println("Number of Days = "
                           + numDays);
    }
}

這是程式碼的輸出:

Number of Days = 29

在switch語句中使用String

在Java SE 7及更高版本中,你可以在switch語句的表示式中使用String物件,以下程式碼示例StringSwitchDemo根據名為monthString的值顯示月份的編號:

public class StringSwitchDemo {

    public static int getMonthNumber(String month) {

        int monthNumber = 0;

        if (month == null) {
            return monthNumber;
        }

        switch (month.toLowerCase()) {
            case "january":
                monthNumber = 1;
                break;
            case "february":
                monthNumber = 2;
                break;
            case "march":
                monthNumber = 3;
                break;
            case "april":
                monthNumber = 4;
                break;
            case "may":
                monthNumber = 5;
                break;
            case "june":
                monthNumber = 6;
                break;
            case "july":
                monthNumber = 7;
                break;
            case "august":
                monthNumber = 8;
                break;
            case "september":
                monthNumber = 9;
                break;
            case "october":
                monthNumber = 10;
                break;
            case "november":
                monthNumber = 11;
                break;
            case "december":
                monthNumber = 12;
                break;
            default: 
                monthNumber = 0;
                break;
        }

        return monthNumber;
    }

    public static void main(String[] args) {

        String month = "August";

        int returnedMonthNumber =
            StringSwitchDemo.getMonthNumber(month);

        if (returnedMonthNumber == 0) {
            System.out.println("Invalid month");
        } else {
            System.out.println(returnedMonthNumber);
        }
    }
}

此程式碼的輸出為8。

switch表示式中的String與每個case標籤關聯的表示式進行比較,就好像正在使用String.equals方法一樣。為了使StringSwitchDemo示例無論何種情況都接受任何monthmonth將轉換為小寫(使用toLowerCase方法),並且與case標籤關聯的所有字串均為小寫。

此示例檢查switch語句中的表示式是否為null,確保任何switch語句中的表示式不為null,以防止丟擲NullPointerException

while和do-while語句

while語句在特定條件為true時繼續執行語句塊,其語法可表示為:

while (expression) {
     statement(s)
}

while語句計算表示式,該表示式必須返回一個布林值,如果表示式的計算結果為true,則while語句將執行while塊中的語句,while語句繼續測試表示式並執行其塊,直到表示式求值為false,使用while語句列印1到10之間的值可以在以下WhileDemo程式中完成:

class WhileDemo {
    public static void main(String[] args){
        int count = 1;
        while (count < 11) {
            System.out.println("Count is: " + count);
            count++;
        }
    }
}

你可以使用while語句實現無限迴圈,如下所示:

while (true){
    // your code goes here
}

Java程式語言還提供了do-while語句,可以表示如下:

do {
     statement(s)
} while (expression);

do-whilewhile之間的區別在於do-while在迴圈的底部而不是頂部計算它的表示式,因此,do塊中的語句總是至少執行一次,如下面的DoWhileDemo程式所示:

class DoWhileDemo {
    public static void main(String[] args){
        int count = 1;
        do {
            System.out.println("Count is: " + count);
            count++;
        } while (count < 11);
    }
}

for語句

for語句提供了一種迭代一系列值的簡潔方法,程式設計師經常將其稱為“for迴圈”,因為它反覆迴圈直到滿足特定條件,for語句的一般形式可表示如下:

for (initialization; termination; increment) {
    statement(s)
}

使用此版本的for語句時,請記住:

  • initialization表示式初始化迴圈,迴圈開始時,它執行一次。
  • termination表示式的計算結果為false時,迴圈終止。
  • 每次迭代迴圈後都會呼叫increment表示式,這個表示式增加或減少一個值是完全可以接受的。

以下程式ForDemo使用for語句的一般形式將數字1到10列印到標準輸出:

class ForDemo {
    public static void main(String[] args){
         for(int i=1; i<11; i++){
              System.out.println("Count is: " + i);
         }
    }
}

該程式的輸出是:

Count is: 1
Count is: 2
Count is: 3
Count is: 4
Count is: 5
Count is: 6
Count is: 7
Count is: 8
Count is: 9
Count is: 10

注意程式碼如何在初始化表示式中宣告變數,此變數的範圍從其宣告擴充套件到由for語句控制的塊的末尾,因此它也可以用在終止和增量表示式中。如果在迴圈外部不需要控制for語句的變數,則最好在初始化表示式中宣告該變數。名稱ijk通常用於控制迴圈,在初始化表示式中宣告它們會限制它們的生命週期並減少錯誤。

for迴圈的三個表示式是可選的,可以建立一個無限迴圈,如下所示:

// infinite loop
for ( ; ; ) {
    
    // your code goes here
}

for語句還有另一種用於迭代集合和陣列的形式,此形式有時也稱為增強的for語句,可用於使迴圈更緊湊,更易於閱讀,要演示,請考慮以下陣列,其中包含數字1到10::

int[] numbers = {1,2,3,4,5,6,7,8,9,10};

以下程式EnhancedForDemo使用增強型for迴圈遍歷陣列:

class EnhancedForDemo {
    public static void main(String[] args){
         int[] numbers = 
             {1,2,3,4,5,6,7,8,9,10};
         for (int item : numbers) {
             System.out.println("Count is: " + item);
         }
    }
}

在此示例中,變數item儲存數字陣列中的當前值,該程式的輸出與之前相同:

Count is: 1
Count is: 2
Count is: 3
Count is: 4
Count is: 5
Count is: 6
Count is: 7
Count is: 8
Count is: 9
Count is: 10

我們建議儘可能使用for語句的這種形式而不是一般形式。

分支語句

break語句

break語句有兩種形式:標記和未標記,你在前面的switch語句討論中看到了未標記的形式,你還可以使用未標記的break來終止forwhiledo-while迴圈,如以下BreakDemo程式所示:

class BreakDemo {
    public static void main(String[] args) {

        int[] arrayOfInts = 
            { 32, 87, 3, 589,
              12, 1076, 2000,
              8, 622, 127 };
        int searchfor = 12;

        int i;
        boolean foundIt = false;

        for (i = 0; i < arrayOfInts.length; i++) {
            if (arrayOfInts[i] == searchfor) {
                foundIt = true;
                break;
            }
        }

        if (foundIt) {
            System.out.println("Found " + searchfor + " at index " + i);
        } else {
            System.out.println(searchfor + " not in the array");
        }
    }
}

該程式在陣列中搜尋數字12,break語句在找到該值時終止for迴圈,然後,控制流轉移到for迴圈後的語句,該程式的輸出是:

Found 12 at index 4

未標記的break語句終止最內層的switchforwhiledo-while語句,但帶標籤的break終止外部語句。以下程式BreakWithLabelDemo與前一個程式類似,但使用巢狀for迴圈來搜尋二維陣列中的值,找到該值後,帶標籤的break將終止外部for迴圈(標記為“search”):

class BreakWithLabelDemo {
    public static void main(String[] args) {

        int[][] arrayOfInts = { 
            { 32, 87, 3, 589 },
            { 12, 1076, 2000, 8 },
            { 622, 127, 77, 955 }
        };
        int searchfor = 12;

        int i;
        int j = 0;
        boolean foundIt = false;

    search:
        for (i = 0; i < arrayOfInts.length; i++) {
            for (j = 0; j < arrayOfInts[i].length;
                 j++) {
                if (arrayOfInts[i][j] == searchfor) {
                    foundIt = true;
                    break search;
                }
            }
        }

        if (foundIt) {
            System.out.println("Found " + searchfor + " at " + i + ", " + j);
        } else {
            System.out.println(searchfor + " not in the array");
        }
    }
}

這是該程式的輸出。

Found 12 at 1, 0

break語句終止帶標籤的語句,它不會將控制流轉移到標籤上,控制流在標記(終止)語句之後立即轉移到語句。

continue語句

continue語句跳過forwhiledo-while迴圈的當前迭代,未標記的形式跳到最內層迴圈體的末尾,並計算控制迴圈的布林表示式。以下程式ContinueDemo逐步執行字串,計算字母“p”的出現次數,如果當前字元不是p,則continue語句將跳過迴圈的其餘部分並繼續執行下一個字元,如果是“p”,程式會增加字母數。

class ContinueDemo {
    public static void main(String[] args) {

        String searchMe = "peter piper picked a " + "peck of pickled peppers";
        int max = searchMe.length();
        int numPs = 0;

        for (int i = 0; i < max; i++) {
            // interested only in p`s
            if (searchMe.charAt(i) != `p`)
                continue;

            // process p`s
            numPs++;
        }
        System.out.println("Found " + numPs + " p`s in the string.");
    }
}

這是該程式的輸出:

Found 9 p`s in the string.

要更清楚地看到此效果,請嘗試刪除continue語句並重新編譯,當你再次執行程式時,計數將是錯誤的,說它找到35個p而不是9個。

標記的continue語句跳過標記有給定標籤的外迴圈的當前迭代,以下示例程式ContinueWithLabelDemo使用巢狀迴圈來搜尋另一個字串中的子字串,需要兩個巢狀迴圈:一個遍歷子字串,一個迭代搜尋的字串,以下程式ContinueWithLabelDemo使用標記形式的continue來跳過外部迴圈中的迭代。

class ContinueWithLabelDemo {
    public static void main(String[] args) {

        String searchMe = "Look for a substring in me";
        String substring = "sub";
        boolean foundIt = false;

        int max = searchMe.length() - 
                  substring.length();

    test:
        for (int i = 0; i <= max; i++) {
            int n = substring.length();
            int j = i;
            int k = 0;
            while (n-- != 0) {
                if (searchMe.charAt(j++) != substring.charAt(k++)) {
                    continue test;
                }
            }
            foundIt = true;
                break test;
        }
        System.out.println(foundIt ? "Found it" : "Didn`t find it");
    }
}

這是該程式的輸出。

Found it

return語句

最後一個分支語句是return語句,return語句從當前方法退出,控制流返回到呼叫方法的位置,return語句有兩種形式:一種是返回值,另一種是不返回值,要返回值,只需將值(或計算值的表示式)放在return關鍵字之後。

return ++count;

返回值的資料型別必須與方法宣告的返回值的型別匹配,當方法宣告為void時,請使用不返回值的return形式。

return;

類和物件課程將涵蓋你需要了解的有關編寫方法的所有內容。

控制流程語句總結

if-then語句是所有控制流語句中最基本的語句,它告訴程式只有在特定測試評估為true時才執行某段程式碼。if-then-else語句在“if”子句求值為false時提供輔助執行路徑,與if-thenif-then-else不同,switch語句允許任意數量的可能執行路徑。whiledo-while語句在特定條件為true時不斷執行語句塊,do-whilewhile之間的區別在於do-while在迴圈的底部而不是頂部計算它的表示式,因此,do塊中的語句總是至少執行一次。for語句提供了一種迭代一系列值的簡潔方法,它有兩種形式,其中一種用於迴圈集合和陣列。


上一篇;表示式、語句和塊

下一篇:類

相關文章