顺序结构

顺序结构是 Java 程序默认的执行流程:按照代码的先后顺序,从上到下依次执行。

例如,下面这段代码会先打印 1,再打印 2,最后打印 3。

java
public class Test1 {
    public static void main(String[] args) {
        System.out.println(1);
        System.out.println(2);
        System.out.println(3);
    }
}

分支结构

顺序结构会一路往下执行,而分支结构可以根据条件决定执行哪一段代码。Java 中常用的分支语句有 if 和 switch。

if 语句

if 适合根据条件进行判断,常见的写法有三种:单分支、双分支和多分支。

第一种:单分支 if

基本格式:

纯文本
if (条件表达式) {
    语句体;
}

先判断括号中的条件表达式。如果结果是 true,就执行大括号里的语句;如果是 false,就跳过这部分代码,继续向下执行。

例如,想判断输入的整数是不是正三位数,只需要判断它是否位于 100~999 之间。写成 Java 条件就是 num >= 100 && num < 1000。

java
import java.util.Scanner;
public class Test1 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int num = sc.nextInt();
        if(num<1000&&num>=100)
        {
            System.out.println(num+"是三位数");
        }
    }
}

这里有两个小细节:

  • 大括号 { 可以另起一行,不过通常建议写在 if 条件这一行的末尾,这样更紧凑。
  • 如果 if 中只有一条语句,大括号可以省略。下面这段代码也可以正常运行:
java
import java.util.Scanner;

public class Test1 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int num = sc.nextInt();
        if (num < 1000 && num >= 100)
            System.out.println(num + "是三位数");
    }
}

不过,如果后面需要再增加语句,忘记补上大括号就容易出问题,所以实际编写时保留大括号通常更稳妥。

判断布尔变量时,还要特别注意 = 和 == 的区别。 比如先定义 boolean flag = false;,本来只是想判断它的值,却手误写成 if (flag = true),这里的 = 是赋值,flag 会被改成 true,整个条件自然也就成立了。

对于布尔变量,直接写 if (flag) 就能判断它是否为 true,不需要额外写 == true。这样更简洁,也能避免把赋值写成比较的失误。

第二种:双分支 if...else

基本格式:

纯文本
if (条件表达式) {
    语句体1;
} else {
    语句体2;
}

程序先判断条件表达式:如果为 true,就执行语句体 1;否则执行语句体 2。两条分支只会选择其中一条,执行完再继续后面的代码。

这种结构就是二选一。例如,判断一个整数是奇数还是偶数:一个整数不是偶数,就是奇数。

java
import java.util.Scanner;

public class Test1 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int num = sc.nextInt();
        if(num%2==0)
        {
            System.out.println(num+"是偶数");
        } else {
            System.out.println(num+"是奇数");
        }
    }
}

这里用 num % 2 == 0 判断能否被 2 整除。成立就打印“偶数”,否则打印“奇数”。

第三种:多分支 if...else if...else

当需要判断的不止两种情况时,可以接着写 else if:

纯文本
if (条件表达式1) {
    语句体1;
} else if (条件表达式2) {
    语句体2;
} else if (条件表达式3) {
    语句体3;
} else {
    其他情况对应的语句体;
}

执行过程可以理解为:

  1. 先判断条件表达式 1,为 true 就执行语句体 1,后面的分支不再判断。
  2. 如果条件 1 不满足,就继续判断条件 2;满足就执行语句体 2。
  3. 依次往下判断,直到找到第一个满足的条件。
  4. 如果所有条件都不满足,就执行最后的 else(如果写了的话)。

例如,我们根据分数划分等级:90 分及以上为 A,80~89 分为 B,70~79 分为 C,60~69 分为 D,60 分以下为 E(这里假设输入的是 0~100 的有效分数)。

java
import java.util.Scanner;

public class Test1 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int score = sc.nextInt();
        if (score >= 90) {
            System.out.println("A");
        } else if (score >= 80) {
            System.out.println("B");
        } else if (score >= 70) {
            System.out.println("C");
        } else if (score >= 60) {
            System.out.println("D");
        } else {
            System.out.println("E");
        }
    }
}

注意一个细节:程序已经判断过 score >= 90,当它继续判断 score >= 80 时,就不需要再写 score < 90 了。因为能走到第二个分支,就说明第一个条件没有成立。

简单来说,if...else if...else 会从上到下依次判断,一旦某个条件成立,就只执行对应分支;如果都不满足,就走最后的 else。

switch 语句

switch 也可以进行多分支选择。与 if...else if 不同,传统的 switch 更适合把一个表达式的结果与几个确定的值进行匹配,而不是直接判断一段数值范围。

基本格式与执行流程

纯文本
switch (表达式) {
    case 值1:
        语句体1;
        break;
    case 值2:
        语句体2;
        break;
    default:
        其他情况的语句体;
        break;
}

这里的 case、break、default 分别起到不同作用:

  • switch (表达式):先计算表达式的值,再寻找匹配的 case。
  • case:标记一个可匹配的值。传统 switch 中常见的是字面量,也可以使用符合要求的编译期常量表达式,但不能直接用普通变量或写成 score >= 90 这样的条件。
  • break:执行到这里就退出当前 switch,避免接着执行后面的分支。
  • default:没有任何 case 匹配时,从这里开始执行。它的作用类似 if...else if...else 结构中最后的 else,用于处理前面都没有匹配到的情况。

传统 switch 常见的匹配类型有 byte、short、char、int、枚举和 String(以及部分对应包装类型)。枚举支持从 Java 5 开始,String 支持从 Java 7 开始。较新的 Java 版本还有更多 switch 能力,这里先掌握最常用的形式。

同一个 switch 中不能出现重复的常量匹配值。

用 switch 判断分数等级

上面使用 if...else if 判断成绩,是直接比较分数区间。换成传统 switch 时,可以利用整数除法:int 类型相除会舍去小数部分,例如 95 / 10 得到 9,83 / 10 得到 8。

这里仍假设输入的是 0~100 分的有效成绩。这样就能把 90~99 分、80~89 分等区间转换成对应的整数;100 分除以 10 得到 10,因此需要用 case 10 单独匹配。

java
import java.util.Scanner;

public class Test1 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int score = sc.nextInt();
        switch(score/10)
        {
            case 10:
                System.out.println("A");
                break;
            case 9:
                System.out.println("A");
                break;
            case 8:
                System.out.println("B");
                break;
            case 7:
                System.out.println("C");
                break;
            case 6:
                System.out.println("D");
                break;
            default:
                System.out.println("E");
                break;
        }
    }
}

当 score / 10 得到 10 或 9 时,都会输出 A;得到 8、7、6 时,分别输出对应等级;其余情况走 default。在 0~100 分的前提下,五个等级就都覆盖到了。

还有一点值得区分:if...else if 是依次判断条件,而 switch 是根据表达式的值找到匹配入口。它们都能完成多分支选择,但具体执行方式并不完全一样。

default 的位置与省略

default 并不一定要放在最后,也可以写在 case 的前面或中间。无论它写在哪里,程序都会先寻找能匹配的 case;只有都匹配不到,才从 default 开始执行。

看下面这段代码,default 被放在最前面:

java
import java.util.Scanner;

public class Test1 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int score = sc.nextInt();
        switch (score / 10) {
            default:
                System.out.println("E");
                break;
            case 10:
                System.out.println("A");
                break;
            case 9:
                System.out.println("A");
                break;
            case 8:
                System.out.println("B");
                break;
            case 7:
                System.out.println("C");
                break;
            case 6:
                System.out.println("D");
                break;
        }
    }
}

虽然 default 写在最前面,但它并不会优先执行。例如,输入 95 时会匹配 case 9,输出 A;输入 50 时没有符合的 case,才会执行 default,输出 E。

可见,default 放在哪里,不影响程序选择哪个分支。这里每个分支都用 break 结束,确保只输出对应的等级。

另外,传统 switch 的 default 也可以省略。如果没有任何 case 匹配、又没有 default,那么这个 switch 就不会执行任何分支。如果需要处理所有未匹配的情况,可以保留 default 作为兜底分支。

case 穿透

传统 switch 中,一旦匹配到某个 case,如果没有遇到 break,就会继续执行后面分支的语句体,不再重新判断后面那些 case 是否匹配。这种现象叫作 case 穿透。

执行过程可以这样理解:先根据表达式的值找到执行入口,然后一路向下执行,直到遇到 break,或者执行到 switch 的右大括号。

例如,把前面成绩判断中的 break 全部去掉。这里让 case 10 和 case 9 共用打印 A 的语句,以便 100 分与 90~99 分从同一处开始执行:

java
import java.util.Scanner;

public class Test1 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int score = sc.nextInt();
        switch (score / 10) {
            case 10:
            case 9:
                System.out.println("A");
            case 8:
                System.out.println("B");
            case 7:
                System.out.println("C");
            case 6:
                System.out.println("D");
            default:
                System.out.println("E");
        }
    }
}

输入 90 时,会从 case 9 开始,依次输出 A、B、C、D、E:

Shell
90
A
B
C
D
E

输入 73 时,会从 case 7 开始,依次输出 C、D、E:

Shell
73
C
D
E

所以,传统 switch 中如果只想执行一个分支,通常需要用 break 防止穿透。当然,在确实需要多个分支共享执行逻辑的场景中,也可以有意利用这种特性。

箭头语法:case ... ->

从 Java 12 开始,switch 的新写法进入预览阶段,并在 Java 14 正式成为标准特性。其中一个明显变化,就是可以把传统的 case 值: 改成 case 值 ->。

这种写法不用在每个分支后手动添加 break,而且不会发生前面那种 case 穿透。先看带大括号的形式:

java
import java.util.Scanner;

public class Test1 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int score = sc.nextInt();
        switch (score / 10) {
            case 10 -> {
                System.out.println("A");
            }
            case 9 -> {
                System.out.println("A");
            }
            case 8 -> {
                System.out.println("B");
            }
            case 7 -> {
                System.out.println("C");
            }
            case 6 -> {
                System.out.println("D");
            }
            default -> {
                System.out.println("E");
            }
        }
    }
}

如果箭头后面只有一条语句,还可以直接省略大括号:

java
import java.util.Scanner;

public class Test1 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int score = sc.nextInt();
        switch (score / 10) {
            case 10 ->
                System.out.println("A");
            case 9 ->
                System.out.println("A");
            case 8 ->
                System.out.println("B");
            case 7 ->
                System.out.println("C");
            case 6 ->
                System.out.println("D");
            default ->
                System.out.println("E");
        }
    }
}

这两种箭头写法都不会向后穿透。case 10 对应 100 分,case 9 对应 90~99 分,二者都输出 A。

这里展示的是 switch 语句的新写法;switch 还可以作为表达式返回结果,不过先掌握分支选择就够用了。

循环结构

如果一段代码需要执行多次,逐行重复写就比较麻烦。这时可以使用循环结构,让程序在满足条件时反复执行同一段代码。

for 循环

for 常见的写法是:

纯文本
for (初始化语句; 条件判断语句; 条件控制语句) {
    循环体语句;
}

可以按下面的顺序理解:

  1. 初始化:先执行初始化语句,这一步只会执行一次。
  2. 判断条件:如果条件为 true,就执行循环体;如果为 false,循环直接结束。
  3. 更新变量:执行完循环体后,执行条件控制语句,再回到第 2 步重新判断。

例如,想打印五遍 helloworld:

java
public class Test1 {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            System.out.println("helloworld");
        }
    }
}

一开始 i = 0,满足 i < 5,于是打印一次,然后执行 i++。接着重新判断,再打印、再加一……

当 i 分别为 0、1、2、3、4 时,循环体都会执行;等 i 增加到 5,判断条件不再成立,循环结束。所以一共执行了 5 次。

在这种写法中,初始化部分只执行一次;之后每次进入循环体前,都要重新判断条件。

while 循环

while 的基本写法是:

纯文本
初始化语句;
while (条件判断语句) {
    循环体语句;
    条件控制语句;
}

这里把初始化和变量更新单独写了出来,方便与上面的 for 对照。实际上,while 的核心语法只有 while (条件) { ... },是否需要初始化或更新变量,要看具体问题。

把刚才打印五遍 helloworld 的例子换成 while:

java
public class Test1 {
    public static void main(String[] args) {
        int i = 0;
        while (i < 5) {
            System.out.println("helloworld");
            i++;
        }
    }
}

程序先判断 i < 5。只要成立,就打印一次并让 i++;当 i 增加到 5,循环结束。和上面的 for 一样,这段代码也会打印五遍。

do...while 循环

do...while 和 for、while 的一个明显区别是:先执行循环体,再判断条件。因此,即使条件一开始就不成立,循环体也会至少执行一次。

基本格式:

纯文本
初始化语句;
do {
    循环体语句;
    条件控制语句;
} while (条件判断语句);

这里的初始化和条件控制语句是为了方便理解循环过程,实际写法可以根据需要调整。注意,do...while 末尾的 while (条件) 后面要有一个分号 ;。

例如:

java
public class Test1 {
    public static void main(String[] args) {
        int i = 10;
        do{
            System.out.println("helloworld");
            i++;
        } while (i < 10);
    }
}

这段代码中,i 一开始就是 10。程序不会先判断 i < 10,而是直接执行 do 中的代码,打印一次 helloworld,然后让 i 增加到 11。接着才判断 i < 10,由于条件不成立,循环结束。

如果换成 for 或 while,在进入循环体前就会判断条件,因此这里一次 helloworld 都不会打印。

do...while 在平时使用得相对少一些,现阶段先记住它至少执行一次循环体的特点即可。

for、while 与 do...while 的区别

for 和 while 都是先判断条件,再执行循环体;do...while 则是先执行一次,再判断是否继续循环。三者都能重复执行代码,只是判断条件的时机不同。

一个容易注意到的区别是循环变量的作用范围:

  • 在上面的 for (int i = 0; ...) 中,i 定义在 for 的初始化部分,离开这个 for 后就不能继续使用。
  • 在上面的 while 示例中,i 定义在循环外,所以循环结束后仍然可以使用。

但这并不是 for 和 while 天生的区别,而是变量声明的位置不同。如果把 for 的控制变量也声明在循环外,循环结束后一样可以访问。

实际选择时,可以简单记成:已知循环次数或明确的遍历范围,常用 for;主要依靠某个结束条件、循环次数不确定时,常用 while;需要至少执行一次循环体时,可以考虑 do...while。 这只是常见习惯,并不是硬性限制。

循环控制语句

有时我们不想等循环自然结束,而是想跳过当前这一轮,或在满足条件时提前停止。这就需要 continue 和 break。

continue:跳过本轮循环

continue 用于跳过当前这一次循环中剩余的语句,继续下一次循环。

例如,遍历 1~10,只打印偶数。如果当前数字是奇数,就执行 continue,跳过后面的打印语句:

java
public class Test1 {
    public static void main(String[] args) {
        for (int i = 1; i <= 10; i++) {
            if (i % 2 != 0)
                continue;
            System.out.println(i);
        }
    }
}

在这个 for 循环中,遇到奇数后执行 continue,会转去执行本轮的 i++,然后重新判断 i <= 10。因此,奇数不会被打印,最后只输出 2、4、6、8、10。

break:提前结束循环

与 continue 只跳过本轮不同,break 会直接结束当前所在的循环,不再进入下一轮。(如果有多层嵌套循环,普通 break 默认只结束它所在的最内层循环。)

例如,我们想从 1 开始,按从小到大的顺序找到 5 个既能被 2 整除、又能被 3 整除的正整数。可以定义一个计数器 count,每找到一个满足条件的数字,就让 count 加 1。当找到第 5 个时,用 break 立即停止循环:

java
public class Test1 {
    public static void main(String[] args) {
        int count=0;
        for(int i=1;i<1000;i++)
        {
            if(i%2==0&&i%3==0)
                count++;
            if (count >= 5)
            {
                System.out.println("已经找到5个可以被2整除又可以被3整除的数字了");
                break;
            }
        }

    }
}

这段代码会从 1 开始逐个检查:如果一个数同时满足 i % 2 == 0 和 i % 3 == 0,就将 count 加 1。符合条件的前五个正整数依次是 6、12、18、24、30。

当 count 增加到 5 时,程序打印提示信息并执行 break,直接退出 for 循环,不必再检查后面的数字。这里的 count 用来记录找到的数量,代码只打印完成提示,并不会逐个打印这五个数字。

谢谢你读到这里。 ✧

聊两句

评论审核后显示

有疑问、补充,或者想交流一下,都可以写在这里。

评论区将在滚动到这里时加载。