今日学习目标
- 熟练掌握
if-else多分支判断的业务逻辑实现,并理解代码复用与方法封装的优化思路。 - 掌握嵌套循环的应用场景,理解质数判断的核心算法逻辑。
- 学会使用
Random类生成随机数据,结合字符数组实现验证码的生成逻辑。 - 梳理基础 Java 程序的完整开发流程:需求分析 → 代码实现 → 流程解析 → 结果验证 → 易错点总结。
案例一:卖飞机票(多分支判断与方法封装)
题目描述
机票价格按照淡旺季、舱位等级收费,用户输入机票原价、乘坐月份和舱位类型(0 - 头等舱,1 - 经济舱),根据以下规则计算优惠后价格:
- 旺季(5-10 月):头等舱 9 折,经济舱 8.5 折
- 淡季(11 月 - 次年 4 月):头等舱 7 折,经济舱 6.5 折
- 同时需要对输入的月份和舱位进行合法性校验,给出错误提示。
方法一:基础if-else直接实现
完整代码
package learn; import java.util.Scanner; public class Example { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入您的飞机票原价:"); double money = sc.nextDouble(); System.out.println("请输入乘坐月份:"); int month = sc.nextInt(); System.out.println("请输入您乘坐的舱位(0-头等舱;1-经济舱):"); int rank = sc.nextInt(); if (month >= 5 && month <= 10) { // 旺季逻辑 if (rank == 0) { money = money * 0.9; } else if (rank == 1) { money = money * 0.85; } else { System.out.println("您输入的舱位有误,请核实!"); } } else if ((month >= 1 && month < 5) || (month > 10 && month <= 12)) { // 淡季逻辑 if (rank == 0) { money = money * 0.7; } else if (rank == 1) { money = money * 0.65; } else { System.out.println("您输入的舱位有误,请核实!"); } } else { System.out.println("您输入的月份有误,请核实!"); } System.out.println("您的机票优惠后为:" + money + "元"); } }代码执行流程解析
- 初始化输入:创建
Scanner对象,读取用户输入的机票原价、月份、舱位信息。 - 旺季判断(5-10 月):
- 外层
if判断月份是否在旺季区间内。 - 内层嵌套
if-else根据舱位类型执行不同折扣计算:头等舱 ×0.9,经济舱 ×0.85,舱位输入非法则输出错误提示。
- 外层
- 淡季判断(1-4 月 或 11-12 月):
else if判断月份是否在淡季区间内。- 内层嵌套
if-else根据舱位类型执行不同折扣计算:头等舱 ×0.7,经济舱 ×0.65,舱位输入非法则输出错误提示。
- 月份非法处理:
else分支处理 1-12 月以外的非法月份输入,输出错误提示。 - 结果输出:打印最终计算的优惠后机票价格。
运行结果说明
输入原价
680、月份7(旺季)、舱位1(经济舱),程序执行后输出:您的机票优惠后为:578.0元,计算逻辑为:680 × 0.85 = 578.0,结果符合预期。
易错点总结
- 月份区间判断逻辑错误:淡季的月份条件必须用
||连接两个区间(1-4 月 和 11-12 月),不能遗漏其中一部分。 - 浮点数计算精度问题:使用
double类型存储价格,计算时可能出现精度偏差,实际开发中可使用BigDecimal优化。 - 输入合法性校验不全:代码中仅对舱位和月份做了判断,未处理非数字输入的异常,实际场景建议增加异常捕获。
- 代码重复问题:旺季和淡季的舱位判断逻辑高度重复,不利于维护。
方法二:方法封装优化实现
完整代码
package learn; import java.util.Scanner; public class Example { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入您的飞机票原价:"); double money = sc.nextDouble(); System.out.println("请输入乘坐月份:"); int month = sc.nextInt(); System.out.println("请输入您乘坐的舱位(0-头等舱;1-经济舱):"); int rank = sc.nextInt(); if (month >= 5 && month <= 10) { // 旺季调用方法,传入对应折扣 money = getMoney(money, rank, 0.9, 0.85); } else if ((month >= 1 && month < 5) || (month > 10 && month <= 12)) { // 淡季调用方法,传入对应折扣 money = getMoney(money, rank, 0.7, 0.65); } else { System.out.println("您输入的月份有误,请核实!"); } System.out.println("您的机票优惠后为:" + money + "元"); } /** * 计算机票优惠价格的方法 * @param money 机票原价 * @param rank 舱位等级(0-头等舱,1-经济舱) * @param v 头等舱折扣 * @param c 经济舱折扣 * @return 优惠后价格 */ public static double getMoney(double money, int rank, double v, double c) { if (rank == 0) { money = money * v; return money; } else if (rank == 1) { money = money * c; return money; } else { System.out.println("您输入的舱位有误,请核实!"); } return money; } }代码执行流程解析
- 主方法逻辑:和基础方法一致,读取用户输入的原价、月份、舱位。
- 分支调用封装方法:根据旺季 / 淡季的判断,调用
getMoney()方法,并传入对应舱位的折扣参数。 - 方法内部处理:
getMoney()接收原价、舱位、头等舱折扣、经济舱折扣四个参数。- 内部通过
if-else判断舱位类型,执行对应折扣计算并返回结果。 - 舱位非法时输出错误提示,返回原始价格。
- 结果输出:主方法接收方法返回的计算结果,打印最终价格。
优化亮点说明
- 消除了重复代码,舱位判断逻辑只写一次,通过传入不同折扣参数适配旺季和淡季场景。
- 代码可读性和可维护性大幅提升,后续修改折扣规则时只需调整方法参数,无需修改多份判断逻辑。
易错点总结
- 方法参数顺序错误:调用
getMoney()时,折扣参数必须和方法定义的顺序一致(先头等舱折扣,再经济舱折扣),否则会导致计算错误。 - 方法返回值遗漏:舱位非法分支中,必须保留
return money;语句,否则会出现编译错误。 - 方法访问修饰符:主方法是
static类型,调用的工具方法也必须声明为static,否则无法直接调用。
案例二:找质数(嵌套循环应用)
题目描述
判断51-100之间有多少个质数,并输出所有质数。
质数定义:大于 1 的自然数,除了 1 和它本身外,不能被其他自然数整除的数。
完整代码
package learn; public class Example { public static void main(String[] args) { int sum = 0; // 统计质数个数 // 遍历51到100的所有数(左闭右开,i < 101) for (int i = 51; i < 101; i++) { boolean result = true; // 标记当前数是否为质数,初始默认是质数 // 用2到i-1的数依次除i,判断是否能整除 for (int j = 2; j < i; j++) { if (i % j == 0) { // 能被整除,说明不是质数 result = false; break; // 无需继续判断,直接跳出内层循环 } } if (result) { sum++; // 质数个数+1 System.out.println(i + "是质数"); } } System.out.println("故51-100之间共有" + sum + "个质数"); } }代码执行流程解析
- 初始化变量:定义
sum变量统计质数总数,初始值为 0。 - 外层循环遍历范围:
for (int i = 51; i < 101; i++)遍历 51 到 100 的所有整数。 - 质数标记初始化:每次外层循环开始,定义
boolean result = true,默认当前数是质数。 - 内层循环判断整除:
for (int j = 2; j < i; j++)用 2 到 i-1 的所有数依次去除当前数i:- 如果
i % j == 0,说明i能被j整除,不是质数,将result设为false,并执行break跳出内层循环(无需继续判断)。
- 如果
- 质数统计与输出:内层循环结束后,判断
result是否为true,如果是则说明是质数,sum自增 1,并打印该质数。 - 最终结果输出:外层循环结束后,打印 51-100 之间的质数总数。
运行结果说明
51-100 之间的质数共有 10 个,和代码输出结果一致,逻辑正确。
易错点总结
- 循环范围错误:外层循环
i < 101才能包含 100,如果写成i < 100会漏掉 100。 - 内层循环起点错误:内层循环必须从
j=2开始,不能从j=1开始(1 能整除所有数,会导致所有数都被误判为非质数)。 break语句遗漏:如果不写break,即使已经判断出不是质数,内层循环仍会继续执行,导致程序效率低下。- 标记变量位置错误:
boolean result = true;必须放在外层循环内部,每次遍历新数时重置标记,否则上一轮的false会影响后续判断。
案例三:开发验证码(随机数与字符数组应用)
题目描述
定义方法实现随机产生一个 5 位的验证码,验证码规则:
- 长度为 5
- 前四位是大写字母或小写字母
- 最后一位是数字
完整代码
package learn; import java.util.Random; public class Example { public static void main(String[] args) { String result = ""; // 1. 创建包含大小写字母的字符数组(共52个字母) char[] box = new char[52]; for (int i = 0; i < box.length; i++) { if (i < 26) { // 前26个位置存储小写字母(a-z,ASCII码97-122) box[i] = (char) (97 + i); } else { // 后26个位置存储大写字母(A-Z,ASCII码65-90) box[i] = (char) (65 + i - 26); } } Random r = new Random(); // 2. 随机生成前4位字母 for (int i = 0; i < 4; i++) { int index = r.nextInt(box.length); // 随机生成数组索引(0-51) result = result + box[index]; // 拼接字符到结果字符串 } // 3. 随机生成最后一位数字(0-9) int num = r.nextInt(10); result = result + num; // 4. 输出最终验证码 System.out.println(result); } }代码执行流程解析
- 字符数组初始化:
- 创建长度为 52 的
char[] box数组,存储大小写字母。 - 前 26 个位置通过
97 + i生成小写字母(a-z),后 26 个位置通过65 + i - 26生成大写字母(A-Z)。
- 创建长度为 52 的
- 生成前 4 位字母:
- 创建
Random类对象,调用nextInt(box.length)生成 0-51 的随机索引。 - 根据随机索引从
box数组中取出字母,拼接到result字符串中,循环 4 次生成前 4 位。
- 创建
- 生成最后一位数字:调用
r.nextInt(10)生成 0-9 的随机数字,拼接到result末尾。 - 输出验证码:打印拼接完成的 5 位验证码。
运行结果说明
程序每次运行都会生成不同的 5 位验证码,例如:
CPzW8,前四位为大小写字母,最后一位为数字,符合题目要求。
易错点总结
- 字符数组生成错误:生成大写字母时,
i - 26是关键偏移量,忘记减去 26 会导致 ASCII 码超出字母范围,生成乱码。 - 随机数范围错误:
nextInt(n)生成的是 0 到 n-1 的数,生成数字时nextInt(10)正确生成 0-9,不能写成nextInt(9)(会漏掉 9)。 - 字符串拼接效率问题:代码中使用
String直接拼接,每次拼接都会创建新对象,验证码长度较长时建议使用StringBuilder优化。 - 索引越界风险:生成随机索引时,
nextInt(box.length)必须使用数组长度作为参数,否则可能生成超出数组范围的索引,导致数组越界异常。
今日学习总结
今天完成了三个 Java 基础案例的实战练习,覆盖了分支判断、嵌套循环、随机数与字符操作三大核心知识点:
- 机票计算案例:从基础的多分支判断,优化为方法封装的实现方式,理解了代码复用和可维护性的重要性,同时掌握了输入校验和浮点数计算的注意事项。
- 质数统计案例:通过嵌套循环实现了质数判断的核心逻辑,理解了标记变量和
break语句在循环中的作用,同时掌握了质数判断的基础算法。 - 验证码生成案例:学会了使用
Random类生成随机数,结合字符数组实现了字母和数字的随机拼接,理解了 ASCII 码和字符数组的应用场景。
三个案例层层递进,从基础逻辑到代码优化,再到实用场景的实现,帮助我巩固了 Java 基础语法,同时理解了程序开发中需求分析、逻辑实现和错误处理的完整流程。后续需要重点练习代码优化思路,减少重复代码,同时关注边界条件和异常处理,提升代码的健壮性。