JAVA语言导学笔记之语言基础知识(2)-控制流语句

控制流语句

源文件内的语句通常按它们出现的顺序从上到下执行。但是,控制流语句通过使用决策、循环和分支来中断执行流程, 使程序能够有条件地执行特定代码块。本节介绍决策语句 (if-then、 if-then-elseor、switch)、循环语句 (forwhiledo-while) 和分支语句 (break,continue,return) 由 Java 编程语言支持。

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语句的末尾。

此外, 打开和关闭大括号是可选的, 前提是 "然后" 子句只包含一个语句:

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

决定何时省略括号是个人品味的问题。省略它们会使代码更加脆弱。如果稍后将第二个语句添加到 "然后" 子句中, 则通常会忘记添加新的所需的大括号。编译器无法捕捉到此类错误;你只会得到错误的结果。

if-then-else or 语句

当 "if" 子句计算为false时, if-then-else or 语句提供了一个执行的辅助路径。如果在自行车不运动时应用刹车, 则可以使用applyBrakes方法中的if-then-else or 语句来采取一些操作。在这种情况下, 操作是简单地打印一条错误消息, 说明自行车已经停止。

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

下面的程序 IfElseDemo根据测试分数的值分配分数: a 分数为90% 或更高, a 评分为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 or 语句不同,switch语句可以有许多可能的执行路径。switch使用byteshort、 charint基元数据类型。它还适用于枚举类型(在Enum 类型中讨论)、 String类以及一些包装某些基元类型的特殊类: CharacterByteShortInteger(在数字和字符串中讨论).

下面的代码示例 SwitchDemo声明一个int , 命名为month, 其值表示一个月。该代码根据month的值, 使用switch语句显示月份的名称。

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块中的语句可以用一个或多个casedefault标签进行标记。switch语句计算其表达式, 然后执行匹配的case标签之后的所有语句。

还可以使用if-then-else or 语句显示月份的名称:

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块中的语句。该程序显示对应于整数month和年份中后续月份的月份:

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, 以便修改代码更容易且容易出错。default节处理所有未由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

在切换语句中使用字符串

在 Java SE 7 和更高版本中, 可以在switch语句的表达式中使用String对象。下面的代码示例 StringSwitchDemo根据String命名month的值显示月份的编号:

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示例无论大小写都接受任何月份,month将转换为小写 (使用 toLowerCase 方法), 并且与case标签关联的所有字符串都是小写。

注意: 本示例检查switch语句中的表达式是否为null确保任何switch语句中的表达式都不是 null, 以防止引发NullPointerException当前。

while和do-while语句声明

while语句在特定条件为true的情况下不断执行语句块。它的语法可以表示为:

while (expression) {
     statement(s)
}

and 语句计算while 表达式, 它必须返回boolean值。如果表达式的while while计算结果为true, 则 and 语句在块中执行语句语句继续测试表达式并执行其块, 直到表达式计算结果为while false使用 Using 语句从1到10打印值可以像在下面的while 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在循环的底部而不是顶部计算其表达式。因此, DoWhileDemo 块中的语句始终至少执行一次, 如以下程序所示: 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语句时, 请记住:

  • 初始化表达式初始化循环;它在循环开始时执行一次。
  • 终止表达式计算结果为false时, 循环终止。
  • 在每次迭代后通过循环调用递增表达式; 否则为此表达式可完全接受递增递减值。

下面的程序 ForDemo使用语句的常规窗体将数字1到10打印到标准输出: for

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语句的变量, 最好在初始化表达式中声明该变量。名称i、 jk通常用于控制循环for;在初始化表达式中声明它们会限制其寿命并减少错误。

for 循环的三表达式是可选的; 否则for可以创建无限循环, 如下所示:

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

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终止for、, 或whiledo-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语句终止最内层的switch、、 forwhiledo-while语句, 但标记为break终止外部语句。下面的程序 BreakWithLabelDemo与上一个程序类似, 但使用循环for嵌套在二维数组中搜索值。找到该值后, 标记为break的外部 for 循环将终止 (标记for"搜索"):

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语句跳过for的当前迭代,, 或while do-while循环。未标记的窗体跳到最里面的循环正文的末尾, 并计算控制循环的boolean表达式。下面的程序 ContinueDemo 通过String对字母 "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使用标记的形式继续跳过外部循环中的迭代。

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" 子句计算为false时, if-then-else or 语句提供了一个执行的辅助路径。if-thenif-then-else不同,switch语句允许任何数量的可能的执行路径。当特定条件为true时, "while" 和 "do-while持续执行语句块。"do-while" 和while之间的差异是do-while在循环的底部而不是顶部计算其表达式。因此, "do" 块中的语句始终至少执行一次。for语句提供了循环访问值范围的紧凑方法。它有两种形式, 其中之一是为循环通过集合和数组而设计的。


阅读更多

扫码向博主提问

二次猿先森

Java开发技术共享,共赢,共有
去开通我的Chat快问
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页