一文彻底吃透Java程序逻辑控制
作者:懒牙牙Pro
前言
Java 程序的执行并非永远是从上到下逐行执行,程序逻辑控制就是通过特定语法结构改变代码的执行顺序、选择执行指定代码、重复执行某段代码的核心语法。是所有编程语言的基础核心,所有复杂的程序功能,都基于以下 3 种基础结构,三者可以任意嵌套组合:
顺序结构:代码从上到下,逐行执行,没有跳转,判断和重复,是最基础的结构
分支结构:根据指定条件的成立或是不成立,选择执行不同的代码块,核心是选择执行
循环结构:根据指定条件,重复执行某一段代码块,核心是重复执行
1. 顺序结构
顺序结构就是代码按照书写的前后顺序从上到下逐行执行,没有任何的判断条件和跳转语句,也无需任何关键字,是程序中最基础的执行结构。
public class SequenceDemo {
public static void main(String[] args) {
System.out.println("aaa");
System.out.println("bbb");
System.out.println("ccc");
}
}
// 运行结果
// aaa
// bbb
// ccc如果改变了代码的书写顺序,那么执行顺序也会随之改变
public class SequenceDemo {
public static void main(String[] args) {
System.out.println("ccc");
System.out.println("bbb");
System.out.println("aaa");
}
}
// 运行结果
// ccc
// bbb
// aaa2. 分支结构
分支结构也叫选择结构,核心是根据条件做选择,Java中为此提供了两种核心分支语法:
if 分支:支持所有条件判断,就比如关系判断,逻辑判断,复杂表达式等,灵活度比较高,使用率最高
switch 分支:等值匹配分支,仅仅支持固定值的等值判断,语法简介,执行效率较高
2.1 if 分支结构
2.1.1 基础用法
if 分支结构是 Java 中最核心最常用的分支结构,支持单分支,双分支,多分支三种写法,满足所有条件判断的场景
单分支
if (条件表达式) {
// 条件为 true 时,执行的代码块
}
// 条件为 false 时,跳过代码块,直接执行后续代码条件表达式的结果必须是 boolean 类型,大括号内是满足条件的执行体。就比如考试成绩在90分以上就奖励一个大鸡腿,代码如下:
// 判断成绩是否大于90分
int score = 95;
if (score >= 90) {
System.out.println("奖励一个大鸡腿!");
}
System.out.println("程序结束");双分支if - else 结构
if (条件表达式1) {
// 条件1为true时执行
} else if (条件表达式2) {
// 条件1为false,条件2为true时执行
} else if (条件表达式3) {
// 条件1、2为false,条件3为true时执行
}
// ... 可以写多个 else if
else {
// 所有条件都为false时,执行的默认代码块
}多选一,从上到下依次匹配条件,只要有一个条件成立,执行对应代码块后直接跳出分支,后续条件不在判断,所有条件都不成立时,执行最后的 else。就如下面这个例子,给成绩评级
// 根据成绩判断等级(多条件匹配)
int score = 92;
if (score >= 90 && score <= 100) {
System.out.println("成绩等级:优秀");
} else if (score >= 80 && score < 90) {
System.out.println("成绩等级:良好");
} else if (score >= 60 && score < 80) {
System.out.println("成绩等级:及格");
} else if (score >= 0 && score < 60) {
System.out.println("成绩等级:不及格");
} else {
System.out.println("输入的成绩不合法!");
}2.1.2 if 嵌套
所谓嵌套就是指在一个结构中完整的包含另一个结构,if 嵌套就是指在 if 结构中还完整包含了另外一个if 结构。如果需要进行多重判断的场景可以使用 if 嵌套,多层级的条件判断,示例如下:
// 先判断是否成年,成年后再判断是否有驾照,有驾照则可以开车
int age = 22;
boolean hasLicense = true;
if (age >= 18) {
System.out.println("已成年");
if (hasLicense) {
System.out.println("有驾照,可以开车");
} else {
System.out.println("无驾照,不能开车");
}
} else {
System.out.println("未成年,禁止开车");
}2.1.3 注意事项
条件表达式必须是 boolean 类型,不能写数值,这是 Java 和 C语言的核心区别
if 条件表达式写判断号
==而非赋值号=浮点数不能直接用 == 判断是否相等,需要考虑误差
如果代码块只有一行语句可以将大括号省略,但是不推荐,容易出现悬垂 else 问题,就比如下面代码:本意是让 else 与第一个 if 进行匹配,但是由于省略了大括号,else 会与最近是 if 进行匹配
// 错误示范:省略大括号,else 会和最近的 if 匹配,逻辑混乱 int a = 5; if (a > 10) if (a < 20) System.out.println("a在10-20之间"); else // 实际匹配的是 内层if,而非外层if System.out.println("a<=10");if 条件表达式后面没有分号,如果笔误加入分号会导致分号成为 if 语句的语句体,而大括号中的代码块成为了和 if 语句无关的代码块,不管是否成立都会执行
int x = 20; if (x == 10); { System.out.println("hehe"); } // 运行结果 hehe由于多分支结构中匹配到成立条件后就会跳出分支,所有建议把概率高的条件写在前面减少条件判断次数,提升程序执行效率
2.2 switch 分支结构
让我们先看看 switch 分支结构的语法组成:
switch (匹配表达式) {
case 常量值1:
// 匹配表达式 == 常量值1 时执行
break; // 跳出switch分支,可选
case 常量值2:
// 匹配表达式 == 常量值2 时执行
break;
// ... 可以写多个 case
default:
// 所有case都匹配失败时执行,可选,位置任意
break;
}switch 是等值匹配分支,仅支持变量值 == 常量值的判断,不支持诸如score >= 60的范围判断。语法较为简洁高效,底层是哈希表匹配,比多层 else if 更为高效。switch 会先计算出匹配表达式的值,然后与case依次匹配,一旦有匹配的值就执行该项下面的语句,直到遇到break才会结束,当表达式的值没有与所列项匹配时,执行default下的语句。需要注意的是如果没有break的话会出现穿透现象。
让我们写一个案例尝试使用 switch 分支结构:根据星期数字输出对应的星期名称
// 根据星期数字,输出对应的星期名称
int week = 3;
switch (week) {
case 1:
System.out.println("星期一");
break;
case 2:
System.out.println("星期二");
break;
case 3:
System.out.println("星期三");
break;
case 4:
System.out.println("星期四");
break;
case 5:
System.out.println("星期五");
break;
case 6:
System.out.println("星期六");
break;
case 7:
System.out.println("星期日");
break;
default:
System.out.println("输入的星期数不合法!");
break;
}注意事项
匹配表达式的数据类型只能是以下类型:byte,char,short,int,String,枚举,不能是long
case后面必须跟常量值,不能是变量或者表达式,多个case不能有相同的常量值
defalut可有可没有,并且可以写在任意位置,但是建议写在最后面
关于穿透现象:什么是穿透现象呢?如果case代码块的末尾没有写break语句,匹配成功后会执行当前case的代码,并且会执行后续所有case的代码,直到遇到break或者switch语句结束,穿透不是bug,而是特性,适合应用在多个常量值对应同一个执行逻辑的场景,如下
// 需求:判断星期是否为工作日(1-5)或休息日(6-7) int week = 2; switch (week) { case 1: case 2: case 3: case 4: case 5: System.out.println("工作日,努力搬砖!"); break; // 匹配1-5任意值,都会执行上面的语句,然后跳出 case 6: case 7: System.out.println("休息日,好好休息!"); break; default: System.out.println("输入错误!"); break; }在JDK14中switch有新的写法,不需要写break,并且不会出现穿透现象,还能够直接返回结果,语法如下:
// 写法1:箭头语法 -> ,无需break,自动跳出 switch (匹配表达式) { case 常量值1 -> 执行语句1; case 常量值2 -> 执行语句2; default -> 执行语句3; } // 写法2:带 yield 返回值,适合多语句执行并返回结果 变量类型 接收变量 = switch (匹配表达式) { case 常量值1 -> 结果值1; case 常量值2 -> { // 多行语句 yield 结果值2; // yield 关键字返回结果 } default -> 结果值3; };// 箭头语法简化switch int week = 3; switch (week) { case 1,2,3,4,5 -> System.out.println("工作日"); // 多个常量值用逗号分隔 case 6,7 -> System.out.println("休息日"); default -> System.out.println("输入错误"); } // yield返回值 int num = 2; String result = switch (num) { case 1 -> "一"; case 2 -> { System.out.println("匹配到了2"); yield "二"; } default -> "未知"; }; System.out.println(result); // 输出:二
3. 循环结构
听名知意,循环结构就是根据具体的循环条件,重复执行某一段代码块,这段重复执行的代码块我们称之为循环体。循环结构有四个要素:初始化条件,循环条件,循环体,更新条件,这四者缺一不可,否则会出现死循环。何为死循环呢?死循环就是指循环条件永远是 true,会无限执行循环体。与 if 一样,如果循环体只有一行语句大括号是可以省略的,但是建议加上。Java中提供了 4 种循环,分别是 for 循环, while 循环,do-while 循环,增强for循环。下面就让我们具体看看这 4 种循环。
3.1 for循环
3.1.1 语法结构
for 循环是 Java 中使用率最高的循环,语法格式整洁,把初始化条件,循环条件,更新条件三个要素集中写到了循环头部,每个条件之间用分号隔开,语法如下:
// 循环四要素集中体现
for (初始化条件; 循环条件; 更新条件) {
// 循环体:满足循环条件时,重复执行的代码块
}执行流程如下:
执行初始化条件,并且只会执行一次
判断循环条件,如果为 false 则循环结束跳出循环,如果为 true 则执行循环体
循环体执行完毕后执行更新条件
回到步骤2,3重复判断循环条件,执行循环体,更新条件,直到循环条件为false
3.1.2 代码示例
1. 打印1-5
for (int i = 1; i < 6; i++) {
System.out.println(i);
}2. 计算1-5的和
int sum = 0;
for (int i = 1; i++; i<=5) {
sum += i;
}
System.out.println(sum);3. 计算5的乘阶
int sum = 1;
for (int i = 1; i++; i<=5) {
sum *= i;
}
System.out.println(sum);4. 计算 1!+2!+3!+4!+5!
int sum = 0;
for (int i = 1; i++; i<=5) {
int tmp = 1;
for (int j = 1; j++; j <=i) {
tmp *= i;
}
sum += tmp;
}
System.out.println(sum);3.1.3 for 嵌套
与 if 分支结构一样,for 循环结构也是可以进行嵌套使用的,外层循环执行一次,内层循环执行全部次数。常见的场景比如打印九九乘法表,二维数组遍历等。下面就以打印九九乘法表为例:
// 九九乘法表
for (int i = 1; i <= 9; i++) { // 外层:行数
for (int j = 1; j <= i; j++) { // 内层:列数,列数<=行数
System.out.print(j + "*" + i + "=" + (i*j) + "\t");
}
System.out.println(); // 换行
}3.1.4 注意事项
初始化条件的作用域:初始化的变量仅在 for 循环内部生效,循环结束后变量失效,外部无法访问
for 后面不要多些分号,否则可能导致循环不能正确执行,建议{与for写在同一行
3.2 while 循环
3.2.1 基本语法
while 循环语法简洁,适合用于循环次数不明确的场景,比如用户输入密码,直到输入正确为止。语法格式如下:
// 1. 初始化条件(写在循环外部)
初始化条件;
while (循环条件) {
// 2. 循环体
循环体代码;
// 3. 更新条件(写在循环体内部,必须写,否则死循环)
更新条件;
}需要注意初始化条件一定要写在循环外部,不然每次循环都会重新初始化,也会导致死循环。执行流程为:
先执行外部初始化条件,并且只会执行一次
判断循环条件,如果为false则结束循环,true则执行循环体
执行循环体后执行更新条件
回到步骤2,3重复判断是否符合循环条件并执行循环体,直到条件为false
3.2.2 代码示例
打印数字1-5
int i = 1; // 初始化 while (i <=5) { // 循环条件 System.out.println(i); // 循环体 i++; // 更新条件 }用户输入密码判断密码是否正确
// 循环次数不确定(直到用户输入正确密码) Scanner sc = new Scanner(System.in); String password = ""; while (!"123456".equals(password)) { // 密码不正确则继续循环 System.out.print("请输入密码:"); password = sc.next(); } System.out.println("密码正确,登录成功!");
3.3 do-while 循环
3.3.1 基本语法
do-while 循环的语法格式和 while 循环类似,只是把循环条件写在了循环体的后面,这也就使得其先执行后判断的语法特性,无论循环条件是否成立循环体至少会执行一次。适用于必须执行一次的场景,比如菜单选择,用户注册的信息验证等。
// 1. 初始化条件
初始化条件;
do {
// 2. 循环体(至少执行一次)
循环体代码;
// 3. 更新条件
更新条件;
} while (循环条件); // 注意:末尾必须加分号!!!执行顺序为:
执行外部初始化条件,并且只会执行一次
先执行一次循环体
执行更新条件
判断循环条件,为false则结束循环,true则回到步骤2继续执行
3.3.2 代码示例
打印数字1-5
int i = 1; do { System.out.println(i); i++; } while (i <=5);即使条件不成立也要执行一次
int j = 10; do { System.out.println("执行了一次循环体"); j++; } while (j <=5); // 条件为false,但循环体已经执行了一次
3.4 增强for循环
3.4.1 基础语法
增强for循环也叫foreach循环,专门用于遍历数组和集合,不需要写下标,也不需要判断长度,自动遍历容器内的所有元素,这一特性让其语法极度简洁,但也因无法获取元素下标,也就无法修改数组的基本类型元素,常用于需要遍历容器,读取元素,不需要操作下表的场景,语法格式如下:
// 遍历数组
for (元素数据类型 变量名 : 数组名) {
// 变量名 就是当前遍历到的元素
}
// 遍历集合(如ArrayList)
for (元素数据类型 变量名 : 集合名) {
// 变量名 就是当前遍历到的元素
}3.4.2 代码示例
遍历数组
// 遍历基本类型数组 int[] arr = {10,20,30,40}; for (int num : arr) { System.out.println(num); // 依次输出:10,20,30,40 } // 遍历字符串数组 String[] strArr = {"Java", "Python", "C++"}; for (String str : strArr) { System.out.println(str); }遍历集合
import java.util.ArrayList; ArrayList<String> list = new ArrayList<>(); list.add("张三"); list.add("李四"); for (String name : list) { System.out.println(name); }
3.4.3 注意事项
增强 for 循环是只读遍历,遍历基本类型数组时,修改遍历变量不会改变原数组的值
遍历引用类型数组或集合时,可以修改元素的属性值,如对象的 name、age
增强 for 循环的底层,本质还是普通 for 循环,只是语法糖
4. 跳转语句
跳转语句可以改变程序的正常执行流程,实现跳出循环、跳过本次循环、结束方法等功能。Java 中提供 3 个核心跳转语句:break、continue、return,都是配合分支和循环使用,是逻辑控制的重要补充。
4.1 break
break 用于跳出循环,在 switch 中匹配到 case 后会执行 break,直接跳出 switch,避免出现穿透现象,在循环结构中,可以终止当前循环,执行循环后的代码。当然,如果遇到多层循环,可以跳出 break 所在层数的循环,也可以配合标签,跳出指定的外层循环。示例如下:
outer: for (int i = 1; i <= 3; i++) { // 外层循环标号outer
inner: for (int j = 1; j <= 3; j++) { // 内层循环标号inner
if (i == 2 && j == 2) {
break outer; // 跳出外层循环,所有循环都结束
}
System.out.println(i + "," + j);
}
}outer 和 inner 只是一个标签名,用于标志当前循环的层数,也可以改为 one, two等。
4.2 continue
continue 用于跳出本次循环,在循环体中如果遇到 continue 会立即跳出本次循环的剩余代码,执行更新条件,然后进入下一次循环的条件判断。与 break 的区别在于 break 会终止整个循环,而 continue 只是跳过本次循环。就比如下面这个案例:打印1-10的所有偶数:
for (int i = 1; i <= 10; i++) {
if (i % 2 != 0) {
continue; // 跳过奇数,直接执行i++,进入下一次循环
}
System.out.println(i); // 只打印偶数
}4.4.3 return
return 是方法级别的跳转语句,作用是结束当前方法的执行,无论方法中是否有循环或是分支,直接退出方法。如果方法有返回值类型,return 必须携带对应类型的返回值,如果是 void 方法,return 可以省略,或是直接写 return。就如下面示例:
// 示例1:void方法中使用return,结束方法
public static void testReturn() {
for (int i = 1; i <= 5; i++) {
if (i == 3) {
return; // 结束方法,后续代码都不执行
}
System.out.println(i); // 只打印1,2
}
System.out.println("方法结束"); // 不会执行
}
// 示例2:有返回值方法中使用return,返回结果
public static int getSum() {
int sum = 0;
for (int i = 1; i <= 10; i++) {
sum += i;
}
return sum; // 返回结果,结束方法
}5. 实战案例
1. 判断一个数是否为素数
素数就是指大于1且除了1和本身不能被其他自然数整除的自然数
int num = 29;
boolean isPrime = true;
if (num <= 1) {
isPrime = false;
} else {
for (int i = 2; i <= Math.sqrt(num); i++) { // 优化:只需遍历到平方根
if (num % i == 0) {
isPrime = false;
break;
}
}
}
System.out.println(num + (isPrime ? "是质数" : "不是质数"));2. 打印水仙花数
水仙花数是指其各位数字的立方和等于该数本身的三位数(如:153 = 1³+5³+3³)
for (int i = 100; i <= 999; i++) {
int ge = i % 10; // 个位
int shi = i / 10 % 10; // 十位
int bai = i / 100; // 百位
if (ge*ge*ge + shi*shi*shi + bai*bai*bai == i) {
System.out.println(i); // 输出:153,370,371,407
}
}3. 猜数字游戏
在完成猜数字游戏之前我们需要了解控制台输入 Scanner 和随机数的生成 Random。Scanner 是 Java 提供的控制台输入工具类,专门用于读取用户从控制台输入的各种数据,Random 是 Java 提供的伪随机数生成工具类,用于生成指定类型的随机数。后面的章节会详细介绍,此处先用
import java.util.Scanner;
import java.util.Random;
public class GuessNumber {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Random rd = new Random();
int randomNum = rd.nextInt(100) + 1; // 生成1-100的随机数
int guessNum = 0;
System.out.println("猜数字游戏开始!(1-100)");
while (guessNum != randomNum) {
System.out.print("请输入你猜的数字:");
guessNum = sc.nextInt();
if (guessNum > randomNum) {
System.out.println("猜大了,再试试!");
} else if (guessNum < randomNum) {
System.out.println("猜小了,再试试!");
} else {
System.out.println("恭喜你,猜对了!");
}
}
}
}总结
到此这篇关于Java程序逻辑控制的文章就介绍到这了,更多相关Java程序逻辑控制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
