程序控制流程:顺序与分支结构
5.1 顺序与分支结构
5.1.1 顺序结构
顺序结构是程序设计中最基础的控制方式,它按照代码语句的书写顺序逐条执行,直到程序运行结束。这种结构简单直观,是所有复杂程序的基础组成部分。
顺序结构示例:
public class FirstProgram {
public static void main(String[] args) {
System.out.println("欢迎学习Java编程!");
}
}
在上述代码中,仅包含一条输出语句,系统会按照从上到下的顺序依次执行该语句,输出"欢迎学习Java编程!"。
5.1.2 分支结构
分支结构也称为选择结构,它根据指定条件表达式的计算结果来选择不同的程序执行路径。Java语言提供了两种实现分支结构的语句:if条件语句和switch多分支语句。
5.1.2.1 if条件语句
if语句通过判断条件的真假来决定是否执行特定的代码块。根据复杂程度的不同,if语句可以分为单分支、双分支和多分支三种形式。
1.单分支结构
if (条件表达式) {
// 条件成立时执行的代码块
}
示例:
int temperature = 25;
if (temperature > 30) {
System.out.println("今天气温很高");
}
System.out.println("程序执行完毕");
2.双分支结构
if (条件表达式) {
// 条件成立时执行的代码块
} else {
// 条件不成立时执行的代码块
}
示例:
int score = 85;
if (score >= 60) {
System.out.println("考试成绩合格");
} else {
System.out.println("考试成绩不合格");
}
System.out.println("程序执行完毕");
3.多分支结构
if (条件表达式1) {
// 条件1成立时执行的代码块
} else if (条件表达式2) {
// 条件2成立时执行的代码块
} else if (条件表达式3) {
// 条件3成立时执行的代码块
} else {
// 所有条件都不成立时执行的代码块
}
示例:
int month = 5;
if (month >= 3 && month <= 5) {
System.out.println("春季");
} else if (month >= 6 && month <= 8) {
System.out.println("夏季");
} else if (month >= 9 && month <= 11) {
System.out.println("秋季");
} else {
System.out.println("冬季");
}
System.out.println("程序执行完毕");
多分支结构的典型应用场景之一是求解一元二次方程。一元二次方程的标准形式为:ax² + bx + c = 0,其中a、b、c为实数常数,且a≠0。根据判别式Δ = b² - 4ac的值,可以判断方程根的情况:
import java.util.Scanner;
import java.lang.Math;
public class QuadraticEquation {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入系数a:");
double coefficientA = scanner.nextDouble();
System.out.print("请输入系数b:");
double coefficientB = scanner.nextDouble();
System.out.print("请输入系数c:");
double coefficientC = scanner.nextDouble();
double discriminant = coefficientB * coefficientB - 4 * coefficientA * coefficientC;
if (discriminant > 0) {
double root1 = (-coefficientB + Math.sqrt(discriminant)) / (2 * coefficientA);
double root2 = (-coefficientB - Math.sqrt(discriminant)) / (2 * coefficientA);
System.out.println("方程有两个不相等的实数根:");
System.out.println("x1 = " + root1);
System.out.println("x2 = " + root2);
} else if (discriminant == 0) {
double root = -coefficientB / (2 * coefficientA);
System.out.println("方程有两个相等的实数根:");
System.out.println("x = " + root);
} else {
double realPart = -coefficientB / (2 * coefficientA);
double imaginaryPart = Math.sqrt(Math.abs(discriminant)) / (2 * coefficientA);
System.out.println("方程有两个共轭复根:");
System.out.println("x1 = " + realPart + " + " + imaginaryPart + "i");
System.out.println("x2 = " + realPart + " - " + imaginaryPart + "i");
}
scanner.close();
}
}
注意事项:
if (1.0 / 1000000 == 0.0) {
System.out.println("极小值被视为零");
}
// 由于浮点数精度问题,上述比较可能产生意外结果
5.1.2.2 嵌套if语句
嵌套if语句是在if或else分支中再次包含完整的if-else结构,用于处理更复杂的条件判断。
基本格式:
if (条件1) {
if (条件2) {
// 条件1和条件2都满足时执行的代码
} else {
// 条件1满足但条件2不满足时执行的代码
}
} else {
// 条件1不满足时执行的代码
}
示例:
int valueX = 8;
int valueY = -2;
if (valueX > 0) {
if (valueY > 0) {
System.out.println("X和Y都是正数");
} else {
System.out.println("X是正数,Y是负数");
}
} else {
System.out.println("X不是正数");
}
嵌套if语句可以有多层嵌套,但嵌套层数不宜过多,否则会导致程序结构复杂、难以理解和维护。建议将复杂的条件判断重构为更清晰的逻辑结构。
5.1.3 switch多分支语句
1.switch语句的基本语法
switch语句根据表达式的值从多个可能的代码块中选择其中一个执行。其语法格式如下:
switch (表达式) {
case 常量1:
// 表达式值等于常量1时执行的代码
break;
case 常量2:
// 表达式值等于常量2时执行的代码
break;
// ... 更多case分支
default:
// 表达式值与所有case常量都不匹配时执行的代码
}
示例:
import java.util.Scanner;
public class DaySelector {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入数字(1-7):");
int dayNumber = input.nextInt();
switch (dayNumber) {
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("输入无效,请输入1-7之间的数字");
break;
}
input.close();
}
}
执行流程说明:
- 首先创建Scanner对象读取用户输入
- 计算switch表达式的值
- 将表达式的值与各case后的常量逐一比较
- 找到匹配的case后执行相应代码块
- 遇到break语句时跳出switch结构
- 若无匹配case,则执行default分支(如果存在)
- 释放Scanner资源
语法特点:
- 表达式支持byte、short、int、char、String等类型
- case后的常量值必须唯一,不能重复
- break语句用于终止switch执行,防止case穿透
- case和default的顺序可以灵活调整,建议将default放在最后
- default分支是可选的
- 每个case分支可以包含任意合法Java语句
- switch结构可以用if-else完全实现,但在多分支场景下switch更简洁清晰
典型应用 - 成绩等级评定:
import java.util.Scanner;
public class GradeEvaluator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入学生成绩:");
int studentScore = scanner.nextInt();
switch (studentScore / 10) {
case 10:
case 9:
System.out.println("优秀");
break;
case 8:
System.out.println("良好");
break;
case 7:
System.out.println("中等");
break;
case 6:
System.out.println("及格");
break;
default:
System.out.println("需要努力");
break;
}
scanner.close();
}
}
2.switch语句的嵌套使用
switch语句内部可以再次嵌套switch语句,用于处理更复杂的多层分支情况:
import java.util.Scanner;
public class ScholarshipEvaluator {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.print("请输入学生成绩:");
int score = scan.nextInt();
switch (score / 10) {
case 10:
case 9:
System.out.println("评级:优秀");
switch (score) {
case 100:
System.out.println("奖励:平板电脑");
break;
case 99:
case 98:
case 97:
case 96:
case 95:
System.out.println("奖励:智能手机");
break;
default:
System.out.println("奖励:学习用品");
break;
}
break;
case 8:
System.out.println("评级:良好");
System.out.println("奖励:笔记本");
break;
case 7:
System.out.println("评级:中等");
break;
case 6:
System.out.println("评级:及格");
break;
default:
System.out.println("评级:需要改进");
break;
}
scan.close();
}
}
3.Java 12至17版本switch语句新特性
(1)Java 12引入的箭头语法
Java 12为switch语句引入了箭头操作符(->)替代传统的冒号(:)语法。使用箭头语法时,case分支不会出现"fall-through"(穿透)现象,无需显式编写break语句,使代码更加简洁可靠。
// 使用Java 12新语法重写成绩评定
switch (score) {
case 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100 -> System.out.println("奖励:平板电脑");
case 80, 81, 82, 83, 84, 85, 86, 87, 88, 89 -> System.out.println("奖励:智能手机");
default -> System.out.println("继续努力");
}
传统写法对比:
public static String getDayType(String day) {
String result;
switch (day) {
case "MONDAY":
case "TUESDAY":
case "WEDNESDAY":
case "THURSDAY":
case "FRIDAY":
result = "工作日";
break;
case "SATURDAY":
case "SUNDAY":
result = "周末";
break;
default:
result = "未知";
break;
}
return result;
}
Java 12+ 简化写法:
public static String getDayType(String day) {
return switch (day) {
case "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY" -> "工作日";
case "SATURDAY", "SUNDAY" -> "周末";
default -> "未知";
};
}
使用示例:
getDayType("MONDAY"); // 返回:工作日
getDayType("FRIDAY"); // 返回:工作日
getDayType("SATURDAY"); // 返回:周末
新语法的主要改进:
- switch可以作为表达式使用,支持返回值
- 使用箭头语法自动防止case穿透,无需break
- 支持单case分支匹配多个值,用逗号分隔
- 代码更加简洁易读
Java 12引入switch表达式主要解决了传统switch的两个问题:
- case穿透问题:传统switch在缺少break时会自动执行下一个case,可能导致难以发现的逻辑错误
- 代码冗余:每个case需要重复相似的代码结构
(2)Java 13引入的yield关键字
Java 13在switch表达式中引入了yield关键字,用于在多分支结构中返回值。当需要处理更复杂的逻辑时,可以使用yield返回结果:
public static String getDayType(String day) {
return switch (day) {
case "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY" -> "工作日";
case "SATURDAY", "SUNDAY" -> "周末";
default -> {
if (day == null || day.isEmpty()) {
yield "输入为空";
} else {
yield "无效日期";
}
}
};
}
使用示例:
getDayType("MONDAY"); // 工作日
getDayType("SATURDAY"); // 周末
getDayType(""); // 输入为空
getDayType("FREDAY"); // 无效日期
(3)Java 17引入的模式匹配
Java 17将模式匹配应用于switch表达式,使得处理不同数据类型更加灵活强大。switch模式匹配支持:类型模式、空模式、守卫模式和常量模式。
类型模式
传统方式处理多种类型需要大量的if-else判断:
public void processData() {
Object[] dataItems = { "消息内容", 256, "标题", "Java", 2.718, "学习资料" };
for (Object item : dataItems) {
if (item instanceof Integer intValue) {
System.out.println("整数类型:" + intValue);
} else if (item instanceof Float floatValue) {
System.out.println("浮点类型:" + floatValue);
} else if (item instanceof Double doubleValue) {
System.out.println("双精度类型:" + doubleValue);
} else if (item instanceof String strValue) {
System.out.println("字符串类型:" + strValue);
} else {
System.out.println("其他类型:" + item);
}
}
}
使用Java 17模式匹配的switch表达式重构:
public void processData() {
Object[] dataItems = { "消息内容", 256, "标题", "Java", 2.718, "学习资料" };
for (Object item : dataItems) {
switch (item) {
case Integer intValue -> System.out.println("整数类型:" + intValue);
case Float floatValue -> System.out.println("浮点类型:" + floatValue);
case Double doubleValue -> System.out.println("双精度类型:" + doubleValue);
case String strValue -> System.out.println("字符串类型:" + strValue);
default -> System.out.println("其他类型:" + item);
}
}
}
Java 17之前,switch表达式仅支持byte、short、char、int等整型类型及其包装类、String和枚举类型。引入类型模式后,switch表达式可以处理任意数据类型。
空模式
Java 17之前,向switch传递null会导致NullPointerException。现在可以通过case null直接处理空值:
public void processData() {
Object[] dataItems = { "消息内容", 256, null, "Java" };
for (Object item : dataItems) {
switch (item) {
case Integer intValue -> System.out.println("整数类型:" + intValue);
case String strValue -> System.out.println("字符串类型:" + strValue);
case null -> System.out.println("空值");
default -> System.out.println("其他类型:" + item);
}
}
}
守卫模式
守卫模式允许在case标签后添加额外判断条件,只有类型匹配且条件为真时才执行该分支:
public void analyzeStrings() {
Object[] dataItems = { "hello", "world", "java", "programming", "hi" };
for (Object item : dataItems) {
switch (item) {
case Integer intValue -> System.out.println("整数类型:" + intValue);
case String strValue && strValue.length() > 5 ->
System.out.println("长字符串:" + strValue);
case String strValue ->
System.out.println("短字符串:" + strValue);
case null -> System.out.println("空值");
default -> System.out.println("其他类型:" + item);
}
}
}
守卫模式使代码更加灵活和富有表现力,能够在单个case中处理复杂的条件判断。