一、程序流程控制
1.1 什么是程序流程控制
-
介绍:程序流程控制是通过特定语法,控制代码执行顺序的机制。默认情况下,代码按 "顺序结构" 自上而下执行,而分支和循环结构能实现 "条件执行" 和 "重复执行"。
-
作用:解决实际业务中的灵活逻辑需求,例如 "成绩≥60 才显示及格"(条件执行)、"循环打印 1-100 的数字"(重复执行),是编写复杂程序的基础。
- 所有复杂程序都是三种基础结构的组合,分支解决 "选做" 问题,循环解决 "重复做" 问题;
- 顺序结构是基础,分支和循环需依赖顺序结构实现逻辑串联。
二、分支结构:按条件执行代码
2.1 if 分支结构(适合 "范围判断")
2.1.1 单路 if(满足条件才执行)
- 介绍:仅包含一个判断条件,条件为true时执行分支内代码,为false时跳过分支,继续执行后续代码。
- 作用:实现 "单一条件触发" 的逻辑(如 "年龄≥18 则允许登录")。
- 使用方式代码:
java
public static void main(String[] args) {
// 语法格式
if (条件表达式) {
// 条件为true时执行的代码块(语句体)
}
// 示例:判断年龄是否成年
int age = 20;
if (age >= 18) {
System.out.println("已成年,可独立办理业务"); // 条件为true,执行此语句
}
System.out.println("程序结束"); // 无论条件是否满足,都会执行(顺序结构)
}
- 条件表达式不能是整数(如if (1)错误),必须返回 boolean 值;
- 若语句体只有 1 行代码,{}可省略,但建议保留(避免后续添加代码时逻辑混乱)。
2.1.2 双路 if-else(二选一执行)
- 介绍:包含 "满足条件" 和 "不满足条件" 两个分支,条件为true时执行if块,为false时执行else块,二者必选其一。
- 作用:实现 "非此即彼" 的二选一逻辑(如 "成绩及格则通过,否则补考")。
- 使用方式代码:
java
// 语法格式
if (条件表达式) {
// 条件为true时执行的代码块
} else {
// 条件为false时执行的代码块
}
// 示例:判断成绩是否及格
int score = 58;
if (score >= 60) {
System.out.println("考试及格,继续加油");
} else {
System.out.println("考试不及格,需要补考"); // 条件为false,执行此语句
}
- else不能单独存在,必须紧跟if;
- if和else的代码块不会同时执行,也不会同时跳过(必然执行其中一个)。
2.1.3 多路 if-else if-else(多选一执行)
- 介绍:包含多个判断条件,按顺序检查条件,满足第一个条件时执行对应分支,后续条件不再检查;所有条件都不满足时,执行else块(可选)。
- 作用:实现 "多优先级条件判断"(如 "根据分数段输出优秀 / 良好 / 及格 / 不及格")。
- 使用方式代码:
java
// 语法格式
if (条件1) {
// 条件1为true时执行
} else if (条件2) {
// 条件1为false、条件2为true时执行
} else if (条件3) {
// 条件1、2为false,条件3为true时执行
} else {
// 所有条件都为false时执行(可选)
}
// 示例:根据分数输出评级
int score = 85;
if (score >= 90) {
System.out.println("评级:优秀");
} else if (score >= 80) {
System.out.println("评级:良好"); // 条件1为false,条件2为true,执行此语句
} else if (score >= 60) {
System.out.println("评级:及格");
} else {
System.out.println("评级:不及格");
}
- 条件必须按 "优先级顺序" 排列(如先判断高分段,再判断低分段),避免逻辑颠倒(如先判断score>=60,会导致高分段也进入及格分支);
- 最多只有一个分支会执行,无else且所有条件不满足时,所有分支都跳过。
2.2 switch 分支结构(适合 "固定值匹配")
- 介绍:通过 "匹配变量值" 执行对应分支,变量类型支持byte、short、int、char、String(JDK7+)、枚举,每个分支用case标识,break用于结束分支。
- 作用:实现 "固定值匹配" 逻辑(如 "根据月份输出季节""根据菜单编号执行功能"),比多路 if 更简洁。
- 使用方式代码:
java
// 语法格式
switch (变量/表达式) {
case 值1:
// 变量等于值1时执行的代码
break; // 跳出switch,避免执行后续case
case 值2:
// 变量等于值2时执行的代码
break;
...
case 值n:
// 变量等于值n时执行的代码
break;
default:
// 变量与所有case值都不匹配时执行(可选,类似else)
break;
}
// 示例:根据月份输出季节
int month = 4;
switch (month) {
case 12:
case 1:
case 2:
System.out.println("季节:冬季"); // month=4不匹配,跳过
break;
case 3:
case 4:
case 5:
System.out.println("季节:春季"); // month=4匹配,执行此语句
break;
case 6:
case 7:
case 8:
System.out.println("季节:夏季");
break;
case 9:
case 10:
case 11:
System.out.println("季节:秋季");
break;
default:
System.out.println("输入的月份无效");
break;
}
- case后的值必须是 "常量"(如1、"winter"),不能是变量(如case num错误);
- 省略break会导致 "case 穿透"(执行当前 case 后,继续执行后续 case,直到遇到 break 或 switch 结束);
- 场景区分:if适合 "范围判断"(如score>=80),switch适合 "固定值匹配"(如month=3)。
三、循环结构:重复执行代码
3.1 while 循环(先判断后执行)
- 介绍:先检查循环条件,条件为true时执行循环体,为false时结束循环;若初始条件为false,循环体一次都不执行。
- 作用:实现 "循环次数未知,但有明确结束条件" 的场景(如 "用户输入'退出'前,一直接收输入")。
- 使用方式代码:
java
// 语法格式
// 1. 初始化循环变量(控制循环的变量)
循环变量类型 变量名 = 初始值;
while (循环条件) { // 条件结果为boolean
// 2. 循环体(重复执行的代码)
// 3. 更新循环变量(避免死循环)
}
// 示例:打印1-5的数字
int i = 1; // 1. 初始化循环变量(从1开始)
while (i <= 5) { // 2. 循环条件(i≤5时继续)
System.out.println("当前数字:" + i); // 3. 循环体(打印i)
i++; // 4. 更新循环变量(i自增1,避免死循环)
}
System.out.println("循环结束"); // 条件为false时执行
- 必须初始化循环变量(否则循环条件无法判断),且循环体中必须更新循环变量(如遗漏i++,会导致死循环,程序一直执行循环体);
- 死循环的常见场景:while (true) { ... }(需在循环体内用 break 手动结束)。
3.2 do-while 循环(先执行后判断)
- 介绍:先执行一次循环体,再检查循环条件;条件为true时继续循环,为false时结束循环,循环体 "至少执行一次"。
- 作用:实现 "循环体必须执行一次" 的场景(如 "先提示用户输入,再判断是否退出")。
- 使用方式代码:
java
// 语法格式
// 1. 初始化循环变量
循环变量类型 变量名 = 初始值;
do {
// 2. 循环体(至少执行一次)
// 3. 更新循环变量
} while (循环条件); // 注意:此处必须加;
// 示例:先打印一次,再判断是否继续
int count = 1;
do {
System.out.println("执行第" + count + "次循环"); // 先执行循环体
count++; // 更新循环变量
} while (count <= 3); // 执行后判断:count=2、3时继续,count=4时结束
// 输出结果:
// 执行第1次循环
// 执行第2次循环
// 执行第3次循环
- 与 while 的核心区别:do-while 循环体 "至少执行一次",while 循环体 "可能一次不执行";
- 语法强制要求:do-while的while后必须加;,遗漏会编译报错。
3.3 for 循环(结构紧凑,适合已知次数)
- 介绍:将 "初始化循环变量、循环条件、更新循环变量" 整合到一行,结构紧凑,执行顺序清晰,是开发中最常用的循环。
- 作用:实现 "循环次数已知" 的场景(如 "循环 10 次""遍历 1-100 的数字")。
- 使用方式代码:
java
// 语法格式(执行顺序:1→2→3→4→2→3→4...)
for (1.初始化循环变量; 2.循环条件; 4.更新循环变量) {
3.循环体(条件为true时执行)
}
// 示例1:打印1-5的数字
for (int i = 1; i <= 5; i++) {
System.out.println("数字:" + i); // 循环5次,i从1到5
}
// 示例2:计算1-100的和
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i; // 每次循环将i累加到sum(sum = sum + i)
}
System.out.println("1-100的和:" + sum); // 输出5050
- 三部分用;分隔,任意部分可省略(但;不能省略),如for (;😉 { ... }会变成死循环;
- 循环变量i在for内部定义时,作用域仅在循环体内(循环结束后无法访问);若需循环后使用,需在外部定义(如int i; for (i=1; i<=5; i++) { ... })。
3.4 循环嵌套(多层重复执行)
- 介绍:在一个循环的 "循环体" 中嵌套另一个循环,外层循环控制 "整体次数",内层循环控制 "每次的重复次数"。
- 作用:实现 "多层重复" 逻辑(如 "打印 5 行 4 列的星号矩阵""遍历二维数组")。
- 使用方式代码:
java
// 示例:打印3行4列的星号矩阵
for (int row = 1; row <= 3; row++) { // 外层循环:控制行数(3行)
for (int col = 1; col <= 4; col++) { // 内层循环:控制每行的列数(4列)
System.out.print("* "); // print不换行,保持同一行
}
System.out.println(); // 内层循环结束后,换行(进入下一行)
}
// 输出结果:
// * * * *
// * * * *
// * * * *
- 执行规律:外层循环执行 1 次,内层循环执行 "完整一轮"(如上述示例:外层 3 次,内层每次 4 次,总执行 3×4=12 次);
- 嵌套层数建议不超过 3 层(层数越多,逻辑越复杂,可读性越低)。
3.5 跳转关键字(break/continue)
3.5.1 break 关键字(强制结束循环)
- 介绍:用于 "强制跳出当前所在的循环" 或 "跳出 switch 分支",执行循环 /switch 之后的代码。
- 作用:实现 "提前结束循环"(如 "找到目标值后,停止遍历")。
- 使用方式代码:
java
// 示例1:循环中用break(找到数字5后停止)
for (int i = 1; i <= 10; i++) {
if (i == 5) {
break; // i=5时,跳出for循环
}
System.out.println("当前i:" + i); // 仅打印1-4
}
System.out.println("循环结束");
// 示例2:嵌套循环中用break(仅跳出内层循环)
for (int row = 1; row <= 3; row++) {
for (int col = 1; col <= 4; col++) {
if (col == 3) {
break; // 仅跳出内层循环,外层继续
}
System.out.print("* ");
}
System.out.println();
}
// 输出结果(每行仅2个星号):
// * *
// * *
// * *
- break 默认只跳出 "当前所在的循环 /switch",嵌套循环中不会跳出外层循环;
- 若需跳出外层循环,可结合 "标签"(如outer: for (...) { inner: for (...) { break outer; } }),但不常用,建议简化嵌套逻辑。
3.5.2 continue 关键字(跳过当前轮循环)
- 介绍:用于 "跳过当前循环的剩余代码",直接进入 "下一次循环的判断"(不会跳出循环,仅跳过当前轮)。
- 作用:实现 "跳过不符合条件的循环轮次"(如 "打印 1-10 中的奇数,跳过偶数")。
- 使用方式代码:
java
// 示例:打印1-10中的奇数(跳过偶数)
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) { // 判断是否为偶数
continue; // 跳过当前轮剩余代码,直接执行i++(下一次判断)
}
System.out.println("奇数:" + i); // 仅打印1、3、5、7、9
}
- continue 与 break 的区别:continue 是 "跳过当前轮,循环继续";break 是 "终止循环,循环结束";
- 循环体中 continue 之后的代码不会执行,需注意代码顺序(如将System.out写在 continue 之后,会导致无法执行)。
四、Random 类:生成随机数
4.1 Random 类的作用与使用步骤
- 介绍:Java 提供的java.util.Random类,用于生成随机整数、随机小数等,常结合分支 / 循环实现 "随机场景"(如猜数字游戏、抽奖)。
- 作用:生成不确定性数据,模拟现实中的随机事件(如 "随机生成 1-100 的数字让用户猜")。
- 使用方式代码(核心步骤):
java
// 步骤1:导入Random类(JDK11+可省略,IDEA会自动导入)
import java.util.Random;
public class RandomDemo {
public static void main(String[] args) {
// 步骤2:创建Random对象
Random random = new Random();
// 步骤3:调用方法生成随机数
// 方法1:生成int类型的随机数(范围:int的取值范围,正负都可能)
int randomInt = random.nextInt();
System.out.println("随机int:" + randomInt);
// 方法2:生成[0, n)范围内的随机整数(n为正整数,包含0,不包含n)
int random0To9 = random.nextInt(10); // 范围:0-9
System.out.println("0-9的随机数:" + random0To9);
// 方法3:生成[a, b]范围内的随机整数(核心公式:nextInt(b - a + 1) + a)
int random1To100 = random.nextInt(100 - 1 + 1) + 1; // 范围:1-100
System.out.println("1-100的随机数:" + random1To100);
}
}
- 必须先创建 Random 对象(new Random()),才能调用生成随机数的方法;
- 生成指定范围[a, b]的随机整数,核心公式为random.nextInt(b - a + 1) + a(如生成 5-10 的数:random.nextInt(6) + 5);
- 若需生成随机小数,可使用random.nextDouble()(范围[0.0, 1.0)),再通过公式缩放至目标范围(如random.nextDouble() * 100生成 0-100 的随机小数)。
五、案例
猜数字游戏案例需求:
- 程序随机生成 1-100 的整数(答案);
- 用户通过键盘录入猜测的数字;
- 程序根据用户输入提示 "猜大了""猜小了""猜对了";
- 猜对后结束程序,未猜对则继续提示用户输入。
实现代码:
java
import java.util.Random;
import java.util.Scanner;
public class GuessNumberGame {
public static void main(String[] args) {
// 1. 生成1-100的随机答案
Random random = new Random();
int answer = random.nextInt(100 - 1 + 1) + 1;
// 2. 创建Scanner对象,接收用户输入
Scanner scanner = new Scanner(System.in);
// 3. 循环让用户猜数字(直到猜对)
while (true) { // 死循环,猜对后用break结束
System.out.print("请输入你猜测的数字(1-100):");
int guess = scanner.nextInt(); // 接收用户输入
// 4. 分支判断:对比猜测值与答案
if (guess > answer) {
System.out.println("猜大了!再试试~");
} else if (guess < answer) {
System.out.println("猜小了!再试试~");
} else {
System.out.println("恭喜你,猜对了!答案就是" + answer);
break; // 猜对,跳出循环,结束程序
}
}
}
}