java实现python的yield关键字的功能-生成器
总结
Java 没有 Python 中 yield 这种 “一键生成器” 的原生语法,但通过以下方式可实现完全等效的 “惰性生成、按需取值” 效果:
1. 基础场景:实现 Iterator/Iterable 接口(最贴近生成器的底层逻辑);
2. 常规场景:Java 8+ Stream API(简洁、高效,推荐);
3. 高并发场景:Java 21+ 虚拟线程 + Stream/Flow;
4. 大文件场景:BufferedReader.lines()(惰性逐行读取,替代 Python yield 读文件)。
基础场景
/* * Copyright (c) [2026] [Allen]. All rights reserved. * * This software is the confidential and proprietary information of * [Allen] ("Confidential Information"). You shall not disclose * such Confidential Information and shall use it only in accordance with * the terms of the license agreement you entered into with [Allen]. * * @author: [Allen] * @date: 2026-02-23 * @version: 1.0 * @description: 斐波那契数列生成器(模拟Python yield关键字的惰性迭代效果) * 实现类似Python yield的按需生成数据能力 */ package com.allen.questions.generator; import java.util.Iterator; // /** * 基于 Iterator/Iterable 手动实现(基础方案)-自定义斐波那契生成器(实现Iterable,支持for-each循环) * Java 中最贴近生成器的核心是迭代器模式:通过实现 Iterator 接口自定义 “按需生成数据” 的逻辑,搭配 Iterable 支持 for-each 循环,模拟 Python 生成器的 “暂停 / 恢复” 和 “惰性生成” 特性。 */ public class FibonacciGenerator implements Iterable<Long> { private final int n; // 生成前n项 public FibonacciGenerator(int n) { this.n = n; } // 核心:实现Iterator,定义按需生成逻辑 @Override public Iterator<Long> iterator() { return new Iterator<Long>() { private long a = 0, b = 1; // 斐波那契初始值 private int count = 0; // 已生成的项数 // 判断是否还有下一项 @Override public boolean hasNext() { return count < n; } // 生成下一项(对应Python的yield) @Override public Long next() { if (!hasNext()) { throw new java.util.NoSuchElementException(); } long current = a; // 本次要返回的值(对应yield a) // 更新值(对应Python中yield后的a,b = b,a+b) long temp = a + b; a = b; b = temp; System.out.printf("a=%d, b=%d%n", a, b); count++; return current; } }; } // 测试代码(对应Python的for循环) public static void main(String[] args) { FibonacciGenerator generator = new FibonacciGenerator(5); for (long num : generator) { // 触发迭代器的next() System.out.println(num); } } }
常规场景
/* * Copyright (c) [2026] [Allen]. All rights reserved. * * This software is the confidential and proprietary information of * [Allen] ("Confidential Information"). You shall not disclose * such Confidential Information and shall use it only in accordance with * the terms of the license agreement you entered into with [Allen]. * * @author: [Allen] * @date: 2026-02-23 * @version: 1.0 * @description: 使用java 8的流 api 实现python yield关键字的效果(懒性求值) */ package com.allen.questions.generator; import java.util.stream.Stream; /** * Java 8+ Stream API(推荐,简洁版 “生成器”)即java 8 引入的 Stream 支持惰性求值,可以通过 Stream.generate() 或 IntStream.iterate() 实现生成器效果,尤其适合无限 / 大数据序列: * 核心特点: * 1. 惰性求值:Stream 不会一次性生成所有数据,只有调用 forEach()/collect() 时才会按需生成; * 2. 简洁高效:无需手动实现迭代器,适合快速开发; * 3. 支持并行处理:parallelStream() 可利用多核,Python 生成器不支持原生并行。 */ public class FibonacciStream { public static void main(String[] args) { // 生成斐波那契数列(前5项),惰性求值 Stream.iterate( new long[]{0, 1}, // 初始值:[a, b] arr -> new long[]{arr[1], arr[0] + arr[1]} // 迭代规则:更新a,b ) .limit(5) // 限制生成5项(对应n=5) .map(arr -> arr[0]) // 取a值(对应yield a) .forEach(num -> { System.out.println(num); // 模拟Python中yield后的print(仅演示,实际可分离逻辑) // long a = num == 0 ? 1 : (num == 1 ? 1 : (num == 1 ? 2 : 3)); // long b = num == 0 ? 1 : (num == 1 ? 2 : (num == 1 ? 3 : 5)); // if (num != 3) { // 最后一项不打印(和Python输出对齐) // System.out.printf("a=%d, b=%d%n", a, b); // } }); } }
高并发场景 && 大文件场景
根据业务需求可以使用并行流
/* * Copyright (c) [2026] [Allen]. All rights reserved. * * This software is the confidential and proprietary information of * [Allen] ("Confidential Information"). You shall not disclose * such Confidential Information and shall use it only in accordance with * the terms of the license agreement you entered into with [Allen]. * * @author: [Allen] * @date: 2026-02-23 * @version: 1.0 * @description: 使用java 21的虚拟现场 api 实现python yield关键字的效果(懒性求值) */ package com.allen.questions.generator; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.nio.file.Paths; /** * 使用java 21的虚拟线程 + java的stream * 逐行惰性读取,内存中始终只存当前行,和 Python yield 效果完全一致; * 资源安全:try-with-resources 自动关闭文件,对应 Python 的 with open()。 */ public class LargeFileGenerator { // 模拟Python的yield读取大文件(返回Iterable,更贴近Python生成器语义) public static void readLargeFile(String filePath) { System.out.println("开始读取文件:" + filePath); // 打印路径,便于排查 // 惰性逐行读取(核心:每行按需生成,对应Python yield) try (BufferedReader br = new BufferedReader(new FileReader(filePath))) { br.lines().parallel() .map(String::strip) // 对应Python的strip() .forEach(line -> { // 逐行打印,模拟Python yield返回每行数据 System.out.println(Thread.currentThread().toString() + "读取到行:" + line); }); System.out.println("文件读取完成"); } catch (IOException e) { // 打印完整异常栈,便于排查路径/文件问题 System.err.println("读取文件失败:" + e.getMessage()); e.printStackTrace(); } } public static void main(String[] args) { // 1. 验证Java版本(确保支持虚拟线程) String javaVersion = System.getProperty("java.version"); System.out.println("当前Java版本:" + javaVersion); // 2. 使用项目相对路径(避免绝对路径问题,data文件夹和generator同级) String filePath = Paths.get( "D:\\java\\my_code\\java-interview-questions\\src\\main\\java\\com\\allen\\questions\\generator\\data\\larg-file.txt" ).toAbsolutePath().toString(); // 3. 启动虚拟线程,并让主线程等待虚拟线程执行完成 Thread virtualThread = Thread.startVirtualThread(() -> readLargeFile(filePath)); // 关键:主线程等待虚拟线程执行完毕(否则JVM直接退出) try { virtualThread.join(); // 等待虚拟线程执行完成 } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.err.println("主线程被中断:" + e.getMessage()); } } }

浙公网安备 33010602011771号