Java实战:机票计算与素数判断算法解析 1. 项目概述Java实战编程的典型场景今天咱们聊聊Java编程中两个非常典型的实战场景机票价格计算系统和素数判断算法。这两个案例看似简单却涵盖了Java基础语法、面向对象思想、算法逻辑等核心知识点是检验Java基本功的绝佳试金石。机票计算系统涉及到用户输入处理、条件判断、浮点数运算等基础但关键的编程技能。而素数判断则考验我们对算法效率的理解和优化能力。这两个案例经常出现在Java初级面试题中也是很多培训机构的教学案例因为它们能很好地展示一个程序员的基础编码能力。提示虽然这些案例看起来基础但很多工作3年以上的开发者在白板编程时仍然会犯低级错误比如忽略边界条件或算法效率问题。2. 机票价格计算系统实现2.1 需求分析与设计思路机票价格计算需要考虑以下几个核心因素基础票价由航线决定燃油附加费固定或按比例机场建设费固定费用折扣率根据购票时间、舱位等变化节假日溢价如春节、国庆等一个健壮的机票计算系统应该能够处理各种异常情况比如非法的票价输入负数或非数字超出合理范围的折扣率特殊乘客儿童、婴儿、老人的优惠政策2.2 核心代码实现import java.util.Scanner; public class TicketPriceCalculator { // 常量定义 private static final double FUEL_SURCHARGE 120.0; private static final double AIRPORT_TAX 50.0; public static void main(String[] args) { Scanner scanner new Scanner(System.in); System.out.print(请输入基础票价: ); double basePrice scanner.nextDouble(); System.out.print(请输入折扣率(0.1-1.0): ); double discount scanner.nextDouble(); System.out.print(是否为节假日(1-是, 0-否): ); int isHoliday scanner.nextInt(); // 输入验证 if(basePrice 0 || discount 0.1 || discount 1.0) { System.out.println(输入参数不合法); return; } // 计算逻辑 double holidaySurcharge isHoliday 1 ? basePrice * 0.2 : 0; double finalPrice (basePrice * discount) FUEL_SURCHARGE AIRPORT_TAX holidaySurcharge; System.out.printf(最终票价为: %.2f元\n, finalPrice); } }2.3 代码优化与异常处理上面的基础版本有几个明显的问题需要优化输入验证不够全面没有考虑多种舱位类型节假日溢价逻辑过于简单缺乏对特殊乘客的考虑改进后的版本应该增加这些功能// 舱位类型枚举 enum CabinClass { ECONOMY, PREMIUM_ECONOMY, BUSINESS, FIRST } // 乘客类型枚举 enum PassengerType { ADULT, CHILD, INFANT, SENIOR } public class EnhancedTicketCalculator { // 更精细化的费用计算 public double calculateTicketPrice(double basePrice, CabinClass cabin, PassengerType passenger, boolean isHoliday) { // 参数校验 if(basePrice 0) { throw new IllegalArgumentException(基础票价必须大于0); } // 舱位系数 double cabinFactor getCabinFactor(cabin); // 乘客折扣 double passengerDiscount getPassengerDiscount(passenger); // 节假日溢价 double holidaySurcharge isHoliday ? basePrice * 0.25 : 0; return (basePrice * cabinFactor * passengerDiscount) getFixedFees(cabin) holidaySurcharge; } // 其他辅助方法... }3. 素数判断算法实现3.1 素数基础概念与判断方法素数是指大于1的自然数中除了1和它本身外不能被其他自然数整除的数。判断一个数是否为素数有多种方法我们从最简单的方法开始逐步优化。最直观的判断方法是试除法对于给定的数n检查2到n-1之间的所有整数是否能整除n。如果都不能则n是素数。public static boolean isPrimeBasic(int n) { if(n 1) return false; for(int i 2; i n; i) { if(n % i 0) return false; } return true; }这个方法虽然正确但效率极低时间复杂度是O(n)。3.2 算法优化思路我们可以通过数学观察来优化算法只需要检查到√n即可如果n不是素数那么它一定有一个因数小于等于√n跳过偶数除了2所有偶数都不是素数预先生成素数表对于多次判断的情况可以使用埃拉托斯特尼筛法优化后的算法public static boolean isPrimeOptimized(int n) { if(n 1) return false; if(n 2) return true; if(n % 2 0) return false; for(int i 3; i * i n; i 2) { if(n % i 0) return false; } return true; }这个版本的时间复杂度降到了O(√n)效率大幅提升。3.3 埃拉托斯特尼筛法实现如果需要频繁判断多个数是否为素数可以使用筛法预先计算public static boolean[] sieveOfEratosthenes(int max) { boolean[] isPrime new boolean[max 1]; Arrays.fill(isPrime, true); isPrime[0] isPrime[1] false; for(int i 2; i * i max; i) { if(isPrime[i]) { for(int j i * i; j max; j i) { isPrime[j] false; } } } return isPrime; }这种方法特别适合需要多次查询素数的情况预处理后每次查询只需O(1)时间。4. 验证码生成与校验4.1 简单数字验证码生成验证码是Web开发中常见的功能用于防止机器人攻击。我们来实现一个简单的数字验证码生成器import java.util.Random; public class CaptchaGenerator { private static final String NUMBERS 0123456789; private static final int LENGTH 6; public static String generate() { Random random new Random(); StringBuilder sb new StringBuilder(); for(int i 0; i LENGTH; i) { int index random.nextInt(NUMBERS.length()); sb.append(NUMBERS.charAt(index)); } return sb.toString(); } public static boolean validate(String input, String captcha) { return input ! null input.equals(captcha); } }4.2 增强型验证码实现更安全的验证码应该包含字母和数字并且区分大小写public class EnhancedCaptcha { private static final String CHAR_SET ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789; private static final int LENGTH 8; public static String generate() { SecureRandom random new SecureRandom(); StringBuilder sb new StringBuilder(); for(int i 0; i LENGTH; i) { int index random.nextInt(CHAR_SET.length()); sb.append(CHAR_SET.charAt(index)); } return sb.toString(); } // 添加验证码过期时间检查 public static boolean validate(String input, String captcha, long generateTime) { long currentTime System.currentTimeMillis(); long expireTime generateTime (5 * 60 * 1000); // 5分钟有效期 if(currentTime expireTime) { return false; } return input ! null input.equals(captcha); } }4.3 验证码图片生成真正的验证码通常以图片形式呈现防止简单的OCR识别import java.awt.*; import java.awt.image.BufferedImage; import java.util.Random; public class ImageCaptcha { private static final int WIDTH 200; private static final int HEIGHT 80; public static BufferedImage generateImageCaptcha(String code) { BufferedImage image new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); Graphics2D g image.createGraphics(); // 设置背景色 g.setColor(Color.WHITE); g.fillRect(0, 0, WIDTH, HEIGHT); // 添加干扰线 Random random new Random(); for(int i 0; i 20; i) { int x1 random.nextInt(WIDTH); int y1 random.nextInt(HEIGHT); int x2 random.nextInt(WIDTH); int y2 random.nextInt(HEIGHT); g.setColor(getRandomColor()); g.drawLine(x1, y1, x2, y2); } // 绘制验证码 g.setFont(new Font(Arial, Font.BOLD, 40)); for(int i 0; i code.length(); i) { g.setColor(getRandomColor()); g.drawString(String.valueOf(code.charAt(i)), 30 * i 20, 50); } g.dispose(); return image; } private static Color getRandomColor() { Random random new Random(); return new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)); } }5. 实战经验与常见问题5.1 机票计算系统的注意事项浮点数精度问题Java中的double类型在进行货币计算时可能会有精度损失。对于金融类计算建议使用BigDecimalBigDecimal basePrice new BigDecimal(1000.00); BigDecimal discount new BigDecimal(0.85); BigDecimal finalPrice basePrice.multiply(discount) .add(new BigDecimal(120.00)) .add(new BigDecimal(50.00));多线程安全问题如果机票计算系统需要处理高并发请求要注意线程安全问题。避免使用共享的可变状态或者使用适当的同步机制。配置化管理燃油附加费、机场建设费等经常变动的参数应该从配置文件中读取而不是硬编码在代码中。5.2 素数算法的性能考量大数判断对于非常大的数如超过10^8即使是优化后的试除法也会很慢。这时可以考虑概率性测试算法如Miller-Rabin测试。缓存优化如果应用需要频繁判断素数可以预先生成素数表并缓存结果。并行计算对于非常大的范围如找出1到10^8之间的所有素数可以考虑将范围分割并并行处理。5.3 验证码系统的安全建议会话管理验证码应该与用户会话绑定防止CSRF攻击。使用安全随机数java.util.Random不够安全应该使用java.security.SecureRandom。限制尝试次数防止暴力破解应该限制单位时间内的验证尝试次数。前端混淆避免直接将验证码以明文形式返回给前端可以考虑分多次请求或添加混淆逻辑。我在实际项目中遇到过验证码被OCR破解的情况后来通过增加干扰线、扭曲文字、背景噪点等措施显著提高了安全性。另一个常见问题是验证码过期时间设置不当要么太短影响用户体验要么太长降低安全性通常5分钟是一个比较合理的折中方案。