关于 Stream
Java 8 中的 Stream API 提供了一种便捷的方法来对集合中的元素进行筛选、排序、聚合等操作。以下介绍其特点、应用场景及关键特性。
特点
- Stream 是一种延迟计算的集合,只有在真正需要使用时才会执行计算操作,可以极大地提高效率。
- Stream 可以处理大量数据,其内部使用了多线程的技术,可以自动并行化处理。
- Stream 可以实现非常复杂的操作,比如 filter、map、reduce 等等。
应用场景
- 数据处理:Stream API 可以用于处理大量的数据,比如从数据库或者文件中读取数据,并对其进行处理。
- 并发编程:Stream API 内部使用了多线程技术,可以实现并发编程,提高程序的执行效率。
- 功能扩展:Stream API 提供了大量的中间操作和终止操作,可以方便地对集合中的元素进行筛选、排序、聚合等操作。
关键特性
- 流(Stream):Stream 是一个数据流,可以看做是一种集合,但是它并不会存储数据,而是通过函数式编程的方式来对数据进行处理。
- 中间操作:Stream 提供了大量的中间操作,比如 filter、map、distinct、sorted、limit 等等,这些中间操作会返回一个新的 Stream。
- 终止操作:Stream 提供了一些终止操作,比如 forEach、count、reduce、collect 等等,这些操作会触发 Stream 的执行,返回一个结果。
- 并行流:Stream 提供了并行流的功能,可以利用多线程的技术来提高程序的执行效率。可以通过 parallelStream() 方法获取一个并行流。
- 支持函数式编程:Stream API 使用函数式编程的方式来处理数据,可以大大简化程序的编写过程。
对于从 Java 迁移到 C++ 的开发者而言,Stream API 非常实用,本文探讨如何在 C++ 中实现类似功能。
实现思路
Java 的实现本质是通过一层一层的回调函数的方式将多个操作串联了起来。那么 C++ 也可以通过回调函数的方式直接实现一个简易的类似 Java 中 Stream 的 API。
也可以通过生产消费者模型来解释,本质都是一样的:有 AB 两个模块,A 负责生产数据,B 负责消费数据,B 不关心 A 怎么生产,A 不关心 B 怎么消费。如果有 ABCD...N 个模块呢,一级级注册回调函数,将这些回调函数级联起来,就很像 Stream 的 API。而且由于都是回调函数,天生是懒加载的,或者说天生支持反应式编程中的背压机制,就是说会根据消费者的消费速度去生产数据。
stream API 的本质就是注册回调函数,并且在合适的时候触发这个回调函数的调用。
接口定义
template<typename T> class Flow {
protected:
/**
* 关键函数定义:
* 此函数的实现定义了何时调用入参的回调函数(数据的生产),当流生产出数据时就调用入参的回调函数,
* 例如:对于一个 vector 的流就是循环调用回调函数
* 对于一个无限流,那么就是死循环调用回调函数
*/
std::function<void(std::function<void(T)>)> consume;
public:
explicit Flow(const std::function<void(std::function<void(T)>)> c) : consume(c) {}
};
关键在于这个成员变量函数 consume:此函数的实现定义了何时调用入参的回调函数(数据的生产),当流生产出数据时就调用入参的回调函数。

