当前位置: 首页 > news >正文

用Java Stream一行代码搞定彩票随机选号(双色球/大乐透)

用Java Stream一行代码搞定彩票随机选号(双色球/大乐透)

每次路过彩票站,总忍不住想试试手气。但机选号码总感觉少了点参与感?不如用Java Stream API自己写个随机选号器,既锻炼编码能力又能享受"定制化"选号的乐趣。下面我们抛开传统循环,用函数式编程思维重构彩票生成逻辑。

1. 从循环到流式操作:思维转换

很多Java开发者习惯用for循环+布尔数组处理随机数去重,比如这样:

boolean[] exists = new boolean[33]; List<Integer> redBalls = new ArrayList<>(); Random rand = new Random(); for(int i=0; i<6; i++){ int num; do { num = rand.nextInt(33)+1; } while(exists[num]); exists[num] = true; redBalls.add(num); } Collections.sort(redBalls);

这种写法虽然直观,但存在几个问题:

  • 代码臃肿:需要手动处理去重、边界条件
  • 状态管理复杂:依赖外部布尔数组记录已选数字
  • 可读性差:业务逻辑被机械的循环控制打断

而用Stream API可以这样重构:

List<Integer> redBalls = new Random().ints(1, 34) .distinct() .limit(6) .sorted() .boxed() .collect(Collectors.toList());

对比两种实现:

特性传统循环方案Stream方案
代码行数10行+1行
可读性需逐行理解控制逻辑声明式表达业务意图
维护成本修改规则需调整多处只需修改参数
并行化潜力需手动实现天然支持parallel()

提示:ints()方法生成的是IntStream,需要boxed()转换为Stream<Integer>才能用常规集合操作

2. 双色球与大乐透的Stream实现

2.1 双色球生成器

双色球规则:从1-33选6个红球,1-16选1个蓝球。完整实现:

public class LotteryGenerator { private static final Random random = new Random(); // 双色球生成 public static void generateSSQ(int count) { System.out.println("双色球机选结果:"); IntStream.range(0, count).forEach(i -> { List<Integer> red = random.ints(1, 34) .distinct() .limit(6) .sorted() .boxed() .collect(Collectors.toList()); int blue = random.nextInt(16) + 1; System.out.printf("第%d注: 红球%s 蓝球%02d%n", i+1, red, blue); }); } }

关键点解析:

  • ints(1, 34):生成1-33范围的随机数流
  • distinct().limit(6):确保6个不重复数字
  • sorted():按升序排列符合彩票显示惯例
  • boxed():将IntStream转为Stream<Integer>

2.2 大乐透生成器

大乐透规则:前区1-35选5个,后区1-12选2个。Stream实现:

public static void generateDLT(int count) { System.out.println("大乐透机选结果:"); IntStream.range(0, count).forEach(i -> { List<Integer> front = random.ints(1, 36) .distinct() .limit(5) .sorted() .boxed() .collect(Collectors.toList()); List<Integer> back = random.ints(1, 13) .distinct() .limit(2) .sorted() .boxed() .collect(Collectors.toList()); System.out.printf("第%d注: 前区%s 后区%s%n", i+1, front, back); }); }

3. 工程化改进与性能考量

3.1 避免重复创建Random实例

原方案每次调用都新建Random对象可能降低性能。改进方案:

// 类级别共享Random实例 private static final ThreadLocalRandom random = ThreadLocalRandom.current(); // 使用方法不变 random.ints(1, 34)...

3.2 并行流优化

对于批量生成场景(如一次生成1000注),可使用并行流:

public static List<String> batchGenerateSSQ(int count) { return IntStream.range(0, count).parallel() .mapToObj(i -> { String red = random.ints(1, 34) .distinct() .limit(6) .sorted() .boxed() .collect(Collectors.toList()) .toString(); int blue = random.nextInt(16) + 1; return String.format("红球%s 蓝球%02d", red, blue); }) .collect(Collectors.toList()); }

性能对比测试(生成10万注):

方式耗时(ms)
顺序流420
并行流110

注意:并行流适合CPU密集型操作,但会增大内存开销

3.3 异常处理与边界条件

健壮的生产代码需要处理极端情况:

public static List<Integer> generateNumbers(int min, int max, int count) { if (count > (max - min + 1)) { throw new IllegalArgumentException( "无法生成"+count+"个不重复的"+min+"-"+max+"范围内的数字"); } return random.ints(min, max + 1) .distinct() .limit(count) .sorted() .boxed() .collect(Collectors.toList()); }

4. 扩展应用:从彩票到实际业务

这种随机采样模式可复用到多种场景:

4.1 抽奖系统实现

public List<String> drawWinners(List<String> participants, int winnerCount) { return ThreadLocalRandom.current() .ints(0, participants.size()) .distinct() .limit(winnerCount) .mapToObj(participants::get) .collect(Collectors.toList()); }

4.2 测试数据生成

生成不重复的测试ID:

List<String> testIds = random.ints(1000, 9999) .distinct() .limit(100) .mapToObj(id -> "TEST_" + id) .collect(Collectors.toList());

4.3 数据库采样

模拟SQL的ORDER BY RAND() LIMIT N

List<User> randomUsers = userRepository.findAll() .stream() .collect(Collectors.collectingAndThen( Collectors.toList(), list -> random.ints(0, list.size()) .distinct() .limit(5) .mapToObj(list::get) .collect(Collectors.toList()) ));

最后分享一个实用技巧:在IntelliJ IDEA中,可以用Ctrl+Alt+V快捷键自动补全Stream操作的变量声明,大幅提升编码效率。比如输入new Random().ints(1,34).distinct().limit(6).sorted()后使用该快捷键,会自动生成完整的收集表达式。

http://www.jsqmd.com/news/661876/

相关文章:

  • Mysql--基础知识点--102--redo log内容
  • Kubernetes资源配额实战:LimitRange配置指南
  • PINN实战:从零构建一个偏微分方程求解器
  • 海洋CMS资源接口实战:XML数据格式与API调用详解
  • STM32 FOC电机库PID调参避坑指南:为什么你的定点参数调不好?
  • 邢台脱发白发理疗养发馆哪家好?黑奥秘参与行业标准制定,专业有据可依 - 美业信息观察
  • AMD平台ESXI 7.0实战:避坑部署Win11与TrueNAS虚拟化存储方案
  • Flask-Admin进阶指南:从基础增删改查到自定义视图和权限控制的完整配置流程
  • 从入门到实战:在UniApp中高效集成uCharts图表(组件与原生双模式详解)
  • 大模型应用开发实战(19)——Andrej Karpathy Skills 为什么突然火了?一份 CLAUDE.md,把 Claude Code 从“会写”拉回“会做事”
  • 2026年团鱼脚鱼甲鱼养殖基地推荐:中华鳖老鳖水鱼专业供应与回收服务选型指南 - 品牌推荐官
  • ContextMenuManager:Windows右键菜单终极解决方案,3个核心功能重塑你的操作效率
  • 别再傻傻地直接扫了!手把手教你用wafw00f在Windows和Kali上优雅地“试探”网站防火墙
  • Intel RealSense D435i数据采集避坑指南:Python脚本获取相机内参、外参并同步保存多传感器图像
  • TMSpeech:Windows本地实时语音识别工具终极配置指南
  • 2026年台式净饮机推荐:碧云泉G7S万相凭实力问鼎年度榜首 - 品牌企业推荐师(官方)
  • 设计模式系列目录
  • 如何用Open-Lyrics实现AI字幕生成与语音翻译:3步完成多语言转换
  • Mysql--基础知识点--101--在线扩容
  • 给企业开发者的MFI指南:当你的App需要连接Honeywell扫描枪时,info.plist和PPID该怎么填?
  • Infinity图像合成实战:如何用比特级建模提升你的AI画质(附GitHub代码)
  • 【技术解析】SwAV:用在线聚类与最优运输破解无监督视觉特征学习难题
  • 考不上高中怎么办,上海华科学校铸就别样精彩 - 品牌企业推荐师(官方)
  • 别再手动传数据了!用MatrikonOPC连接Matlab和NX MCD,实现自动化联合仿真
  • 远程生理信号监测终极指南:rPPG框架的完整实践教程
  • MOTR:基于Transformer的端到端多目标跟踪框架深度剖析
  • 仅限首批200家企业的AGI治理合规工具包泄露(源自2026奇点大会技术委员会内部推演)
  • ESP32 UI美化秘籍:手把手教你从阿里图标库(iconfont)扒图标,集成到LVGL界面里
  • ESP32的GPIO不够用?手把手教你用I2C和PCA9557扩展8个IO(附完整代码)
  • Wan2.2-I2V-A14B效果对比评测:YOLOv11目标检测框引导下的精准视频生成