流压缩器
内容提要
Java 22引入了流收集器的预览API,允许在流管道上进行自定义中间操作。这可以用于实现一个zip()方法,用于将两个Java流进行压缩。收集器接受一个要与之压缩的流和一个函数,并返回压缩后的结果。实现使用一个整合器将函数应用于两个流的元素对。收集器不能并行化,并且要求两个输入流具有相同的长度。
延伸解读
为何需要自定义 zip 操作
Java 标准 Stream API 并未提供 zip() 方法,尽管早期预览版曾考虑加入,但在 Java 8 正式发布前被移除。因此,若需按位置连接两个流,开发者通常依赖 Google Guava 等第三方库。Java 22 引入的流收集器(Gatherer)预览 API 填补了这一空白,允许以自定义中间操作的方式实现 zip,而无需等待官方 API 扩展。
实现机制与关键限制
该实现通过 Gatherer 的 Integrator 逐元素处理:对主流的每个元素,从第二个流的 Spliterator 中取一个元素,应用给定函数后推送到下游。当任一流耗尽时即停止发射,因此要求两个输入流长度相同,否则会错位压缩。此外,由于无法在并行子步骤中访问第二个流的 Spliterator,该收集器不能并行化,只能串行执行。
使用方式与代码可读性
借助少量“构建器风格”的胶水代码,可以写出 letters.stream().gather(zip(numbers).with((letter, i) -> i + "-" + letter)) 这样的链式调用,最终收集为列表。作者还提供了 ObjToIntZipper 以避免 int 流装箱。尽管 Gatherer 涉及三个类型参数,但作者认为其 API 在实际使用中相当直观,整体代码可读性较好。
Q&A
Java 22的流收集器预览API有什么新功能?
Java 22引入了流收集器的预览API,允许在流管道上进行自定义中间操作,支持实现zip()方法来压缩两个流。
如何使用Java的zip()方法压缩两个流?
可以通过创建一个收集器,接受要压缩的流和一个函数,应用于两个流的元素对,返回压缩后的结果。
zip()方法的实现有什么限制?
zip()方法要求两个输入流具有相同的长度,并且该收集器不能并行化。
zip()方法的实现如何处理流的耗尽?
当其中一个流耗尽时,zip()方法会停止发出元素,可以实现类似'左连接'的语义。
可以给出zip()方法的使用示例吗?
可以使用zip()方法将字母流和数字流结合,例如将字母与其索引连接,结果为"0-a", "1-b"等。
流收集器的预览API与传统收集器有什么不同?
流收集器的预览API允许添加自定义中间操作,而传统收集器主要用于终端操作。