Java入门学习笔记:程序流程控制
程序流程控制决定了代码的执行顺序,是简单输出语句,到能实现复杂业务逻辑的关键一步。
一、程序的三大基本执行结构
Java中所有代码的执行逻辑,都可以归为三种基础结构,所有复杂的程序都是这三种结构的组合与嵌套。
1. 顺序结构
最基础的执行结构,代码会自上而下依次执行,没有任何判断和跳转,是绝大多数基础代码都默认遵循这个结构。
public class Test {
public static void main(String[] args) {
// 会按照从上到下的顺序,依次输出A、B、C
System.out.println("A");
System.out.println("B");
System.out.println("C");
}
}
2. 分支结构
根据预设的条件,选择性地执行某一段代码,实现逻辑的判断与分流。Java中主要提供了if和switch两种分支实现方式。
3. 循环结构
控制某一段代码重复执行多次,大幅减少冗余代码,灵活控制程序的执行节奏。Java中提供了for、while、do-while三种循环实现方式。
二、分支结构详解
分支结构的核心是「条件判断」,根据判断结果的真假,决定执行哪一段代码,是实现业务逻辑判断的核心语法。
1. if分支结构
if分支是最常用的分支语法,支持区间判断、复杂条件判断,功能覆盖范围最广,共有三种书写形式。
(1)单if分支
仅针对单个条件做判断,条件为true时执行对应代码,为false则跳过。
语法格式:
if (条件表达式) {
语句体; // 条件为true时执行的代码
}
执行流程:
- 先计算条件表达式的结果,结果为布尔类型(
true/false) - 结果为
true,执行大括号内的语句体;结果为false,直接跳过整个分支
使用注意:
if(条件)后的括号不能跟分号;,否则大括号内的代码将不受if条件控制- 如果大括号内只有一行代码,大括号可以省略,但不推荐,会降低代码可读性
示例代码:
// 判断BMI是否在正常范围
public class BMITest {
public static void main(String[] args) {
double weight = 65; // 体重 单位:kg
double height = 1.75; // 身高 单位:m
double bmi = weight / (height * height);
// 单if判断:BMI正常时输出提示
if (bmi >= 18.5 && bmi <= 24.9) {
System.out.println("你的BMI指数正常,继续保持!");
}
}
}
(2)if-else双分支
针对一个条件,提供「满足/不满足」两种执行路径,非此即彼。
语法格式:
if (条件表达式) {
语句体1; // 条件为true时执行
} else {
语句体2; // 条件为false时执行
}
执行流程:
- 计算条件表达式的布尔结果
- 结果为
true,执行语句体1;结果为false,执行语句体2
示例代码:
// 判断一个数是奇数还是偶数
public class OddEvenTest {
public static void main(String[] args) {
int num = 15;
if (num % 2 == 0) {
System.out.println(num + "是偶数");
} else {
System.out.println(num + "是奇数");
}
}
}
(3)if-else if-else多分支
针对多个连续的条件做判断,从上到下依次匹配,匹配到第一个符合的条件后,执行对应代码并结束整个分支,适合多区间、多条件的判断场景。
语法格式:
if (条件表达式1) {
语句体1;
} else if (条件表达式2) {
语句体2;
} else if (条件表达式3) {
语句体3;
}
// 可以写任意多个else if
else {
语句体n; // 所有条件都不满足时,执行这里的代码
}
执行流程:
- 先判断条件1,结果为
true则执行语句体1,分支结束;为false则继续判断条件2 - 条件2为
true则执行语句体2,分支结束;为false则继续判断后续条件 - 若所有条件都为
false,则执行else中的语句体n
示例代码(完整BMI指数判断):
public class BMIFullTest {
public static void main(String[] args) {
double weight = 80;
double height = 1.75;
double bmi = weight / (height * height);
System.out.println("你的BMI指数为:" + bmi);
// 多分支判断BMI所处区间
if (bmi < 18.5) {
System.out.println("体重过低");
} else if (bmi <= 24.9) {
System.out.println("体重正常");
} else if (bmi <= 29.9) {
System.out.println("超重");
} else {
System.out.println("肥胖");
}
}
}
2. switch分支结构
switch分支专门针对固定值匹配的场景,通过匹配表达式的值与case后的值是否相等,决定执行哪条分支,代码结构更清晰,性能更优。
(1)基础语法与执行流程
语法格式:
switch(表达式) {
case 值1:
执行代码1;
break; // 跳出分支,避免穿透
case 值2:
执行代码2;
break;
// 可以写任意多个case
default:
执行代码n; // 所有case都不匹配时,执行这里的代码
}
执行流程:
- 先计算表达式的值,再拿着这个值与case后的值依次匹配
- 与哪个case的值匹配成功,就执行该case块内的代码,遇到
break就跳出整个switch分支 - 所有case都匹配失败,则执行
default块内的代码
(2)使用注意事项
- 表达式的类型有严格限制:仅支持
byte、short、int、char,JDK5开始支持枚举,JDK7开始支持String,不支持double、float、long - case后的值不允许重复,且必须是字面量,不能是变量
- 正常使用时不要忘记写
break,否则会出现case穿透现象
(3)case穿透性的应用
当多个case分支需要执行的代码完全相同时,可以利用穿透性简化代码,不用重复书写相同逻辑。
示例代码:
// 根据星期数,输出当日安排
public class WeekPlanTest {
public static void main(String[] args) {
int week = 3;
switch (week) {
case 1:
System.out.println("埋头苦干,解决bug");
break;
// 周二、周三、周四执行相同逻辑,利用穿透简化
case 2:
case 3:
case 4:
System.out.println("请求大牛程序员帮忙");
break;
case 5:
System.out.println("整理代码");
break;
// 周六、周日执行相同逻辑
case 6:
case 7:
System.out.println("打游戏放松");
break;
default:
System.out.println("输入的星期数有误");
}
}
}
3. if与switch的适用场景对比
| 语法 | 核心优势 | 最佳适用场景 |
|---|
| if | 功能更强大,支持区间判断、复杂逻辑判断 | 条件为区间范围、需要做复杂逻辑运算的场景 |
| switch | 代码结构清晰,固定值匹配性能更优 | 条件为单个固定值、多个值匹配的场景 |
三、循环结构详解
循环结构的核心是「重复执行」,可以让一段代码按照规则循环执行,避免手动重复书写代码,是批量处理数据、重复执行逻辑的核心语法。
1. for循环
for循环是最常用的循环语法,适合明确知道循环次数的场景,语法结构紧凑,循环变量的生命周期仅在循环内有效,更安全。
(1)基础语法与执行流程
语法格式:
for (初始化语句; 循环条件; 迭代语句) {
循环体语句; // 重复执行的代码
}
执行流程:
// 示例代码
for (int i = 0; i < 3; i++) {
System.out.println("Hello World");
}
- 循环开始时,先执行一次初始化语句
int i = 0,整个循环只会执行一次 - 判断循环条件
i < 3,结果为true则执行循环体,结果为false则直接结束循环 - 循环体执行完毕后,执行迭代语句
i++,然后再次回到步骤2判断循环条件 - 重复步骤2-3,直到循环条件为
false,循环结束
(2)案例
求1-5之间的数字和
public class SumTest {
public static void main(String[] args) {
int sum = 0; // 定义求和变量
// 循环生成1-5的数字
for (int i = 1; i <= 5; i++) {
sum += i; // 累加每个数字到sum中
}
System.out.println("1-5的和为:" + sum); // 输出结果15
}
}
查找所有水仙花数
水仙花数定义:是一个三位数,且个位、十位、百位的数字立方和等于原数。
public class NarcissisticNumberTest {
public static void main(String[] args) {
int count = 0; // 统计水仙花数的个数
// 遍历所有三位数
for (int i = 100; i <= 999; i++) {
// 提取个位、十位、百位
int ge = i % 10;
int shi = i / 10 % 10;
int bai = i / 100 % 10;
// 判断是否符合水仙花数规则
if (ge*ge*ge + shi*shi*shi + bai*bai*bai == i) {
System.out.println(i);
count++;
}
}
System.out.println("水仙花数总共有:" + count + "个");
}
}
2. while循环
while循环的功能与for循环完全一致,核心区别是适合不知道循环次数的场景,循环变量在循环结束后仍可使用。
(1)基础语法与执行流程
语法格式:
初始化语句;
while (循环条件) {
循环体语句;
迭代语句;
}
执行流程:
- 先执行一次初始化语句
- 判断循环条件,结果为
true则执行循环体和迭代语句,结果为false则结束循环 - 每次迭代语句执行完毕后,再次回到步骤2判断循环条件,重复执行
(2)经典实战案例
纸张折叠多少次能达到珠峰高度
珠峰高度8848.86米=8848860毫米,纸张厚度0.1毫米,每次折叠厚度翻倍,求折叠次数。
public class PaperFoldTest {
public static void main(String[] args) {
double peakHeight = 8848860; // 珠峰高度 单位:毫米
double paperThickness = 0.1; // 纸张初始厚度 单位:毫米
int count = 0; // 统计折叠次数
// 不知道循环次数,用while循环
while (paperThickness < peakHeight) {
paperThickness *= 2; // 每次折叠厚度翻倍
count++;
}
System.out.println("需要折叠的次数:" + count);
}
}
3. do-while循环
do-while循环的核心特点是先执行,后判断,哪怕循环条件一开始就不成立,循环体也会至少执行一次。
(1)基础语法与执行流程
语法格式:
初始化语句;
do {
循环体语句;
迭代语句;
} while (循环条件);
执行流程:
- 先执行一次初始化语句,然后直接执行循环体和迭代语句
- 执行完毕后,再判断循环条件,结果为
true则再次执行循环体,结果为false则结束循环
(2)适用场景
适合需要先执行一次操作,再判断是否继续循环的场景,比如12306抢票时,先执行一次刷票,再判断是否需要继续刷新。
4. 三种循环的核心区别总结
执行顺序区别:
for和while:先判断循环条件,再执行循环体,条件不成立则一次都不执行do-while:先执行循环体,再判断循环条件,至少执行一次
使用场景区别:
- 明确知道循环次数:优先使用
for循环 - 不知道循环次数:优先使用
while循环
循环变量区别:
for循环的初始化变量定义在循环内,仅在循环中可使用while和do-while的初始化变量定义在循环外,循环结束后仍可继续使用
5. 死循环
死循环是指循环条件一直为true,会一直执行下去的循环,除非手动干预,否则不会停止。在服务器程序、持续监听的场景中非常常用。
三种常见写法:
// 1. for循环死循环
for ( ; ; ) {
System.out.println("死循环执行");
}
// 2. while循环死循环(最经典、最常用)
while (true) {
System.out.println("死循环执行");
}
// 3. do-while循环死循环
do {
System.out.println("死循环执行");
} while (true);
6. 循环嵌套
循环嵌套指的是在一个循环内部,又包含了另一个循环,外层循环每执行一次,内层循环会完整执行完一轮。
示例代码:
public class LoopNestTest {
public static void main(String[] args) {
// 外层循环控制行数
for (int i = 1; i <= 4; i++) {
// 内层循环控制每行的星号个数
for (int j = 1; j <= 5; j++) {
System.out.print("*");
}
// 每行打印完后换行
System.out.println();
}
}
}
四、循环控制关键字:break & continue
break和continue是专门用来控制循环执行流程的关键字,可以灵活地中断循环、跳过某次循环。
1. break关键字
核心作用:跳出并结束当前所在的整个循环,也可以用来结束switch分支的执行。
使用限制:只能在循环和switch分支中使用。
示例代码:
// 循环到5时,结束整个循环
public class BreakTest {
public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {
if (i == 5) {
break; // 遇到5,直接结束整个循环
}
System.out.println(i);
}
// 最终只会输出1、2、3、4
}
}
2. continue关键字
核心作用:跳出当前循环的本次执行,直接进入循环的下一次迭代。
使用限制:只能在循环中使用。
示例代码:
// 跳过偶数,只输出奇数
public class ContinueTest {
public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // 遇到偶数,跳过本次循环,进入下一次
}
System.out.println(i);
}
// 最终输出1、3、5、7、9
}
}
五、补充工具:Random随机数生成
在很多实战案例中(比如猜数字游戏、验证码生成),我们需要生成随机数,Java提供了java.util.Random类专门用来处理随机数生成。
1. 使用步骤
导包:在类的最上方导入Random类
import java.util.Random;
创建Random对象
Random r = new Random();
调用方法生成随机数
// 生成0到9之间的随机数(包含0,不包含10)
int num = r.nextInt(10);
2. 区间随机数生成技巧
nextInt(n)只能生成0 ~ n-1之间的随机数,要生成指定区间[min, max]的随机数,使用减加法:
公式:r.nextInt(max - min + 1) + min
示例:
// 生成1-100之间的随机数
int num1 = r.nextInt(100) + 1;
// 生成65-91之间的随机数
int num2 = r.nextInt(27) + 65;
六、案例
求三个整数中的最大值
import java.util.Scanner;
public class MaxNumberTest {
public static void main(String[] args) {
// 创建键盘录入对象
Scanner sc = new Scanner(System.in);
// 录入三个整数
System.out.println("请输入第一个整数:");
int a = sc.nextInt();
System.out.println("请输入第二个整数:");
int b = sc.nextInt();
System.out.println("请输入第三个整数:");
int c = sc.nextInt();
// 用if分支求最大值
int max;
if (a >= b && a >= c) {
max = a;
} else if (b >= a && b >= c) {
max = b;
} else {
max = c;
}
// 输出结果
System.out.println("三个数中的最大值是:" + max);
sc.close();
}
}
根据工龄计算涨薪额度
import java.util.Scanner;
public class SalaryTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 录入工龄和基本工资
System.out.println("请输入你的工作工龄:");
int workYears = sc.nextInt();
System.out.println("请输入你的基本工资:");
int baseSalary = sc.nextInt();
// 计算应涨工资
int addSalary;
if (workYears >= 10 && workYears < 15) {
addSalary = 20000;
} else if (workYears >= 5 && workYears < 10) {
addSalary = 10000;
} else if (workYears >= 3 && workYears < 5) {
addSalary = 5000;
} else if (workYears >= 1 && workYears < 3) {
addSalary = 3000;
} else {
addSalary = 0;
}
// 输出结果
System.out.println("您目前工作了" + workYears + "年,基本工资为 "
+ baseSalary + "元, 应涨工资 " + addSalary + "元,涨后工资 " + (baseSalary + addSalary) + "元");
sc.close();
}
}
求1-100中既是3又是5的倍数的数字及和
public class MultipleSumTest {
public static void main(String[] args) {
int sum = 0;
// 遍历1-100的数字
for (int i = 1; i <= 100; i++) {
// 判断既是3的倍数,又是5的倍数
if (i % 3 == 0 && i % 5 == 0) {
System.out.println(i);
sum += i;
}
}
System.out.println("以上满足条件的数字之和:" + sum);
}
}
筛选指定区间内符合条件的三位数
需求:录入一个大于100的三位数,打印100到该数字之间,满足「个位数不为7、十位数不为5、百位数不为3」的数字、个数及和。
import java.util.Scanner;
public class NumberFilterTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入大于100的三位整数:");
int maxNum = sc.nextInt();
int count = 0;
int sum = 0;
// 遍历100到输入的数字
for (int i = 100; i <= maxNum; i++) {
// 提取个位、十位、百位
int ge = i % 10;
int shi = i / 10 % 10;
int bai = i / 100 % 10;
// 判断条件
if (ge != 7 && shi != 5 && bai != 3) {
System.out.println(i);
sum += i;
count++;
}
}
// 输出统计结果
System.out.println("以上满足条件的数字之和:" + sum);
System.out.println("以上满足条件的数字个数:" + count);
sc.close();
}
}
筛选符合条件的四位数
需求:打印所有四位数中,满足「个位 + 千位 == 百位 + 十位」的数字,并统计总个数。
public class FourDigitFilterTest {
public static void main(String[] args) {
int count = 0;
// 遍历所有四位数
for (int i = 1000; i <= 9999; i++) {
// 提取个位、十位、百位、千位
int ge = i % 10;
int shi = i / 10 % 10;
int bai = i / 100 % 10;
int qian = i / 1000 % 10;
// 判断条件
if ((ge + qian) == (bai + shi)) {
System.out.print(i + " ");
count++;
// 每行输出5个数字,换行
if (count % 5 == 0) {
System.out.println();
}
}
}
// 输出总个数
System.out.println("\n以上满足条件的四位数总共有 " + count + " 个");
}
}