最近要学习flink 流处理框架,其中有些概念一上来看还是还是比较confuse。
想起java8 中的stream 编程,他们的设计哲学相似,只不过flink可以处理大规模的数据集。
这篇文章将深入学习,java8 的stream api以及函数式编程。
在网上个人能找到的资料中,下面的git 是写的最好,最深入浅出的。
https://github.com/CarpenterLee/JavaLambdaInternals
对于stream系统的学习,大家可以看上面的git,下面是个人针对上述主题的学习和理解。
1. stream api 的好处
-函数式编程风格,带来的链式的代码,同样的任务,可以用更加简洁的代码来实现。
-我一直认同,编程是关于交流的艺术,简洁意味着交流效率的提升。 函数式风格的代码,其实是更加贴近自然语言的代码
就是一种say what i want to do 的语言, 而不是一种 how i should do 的语言,他告诉计算机要干什么,而不是告诉
计算机每一步具体的细节,这样的哲学就像SQL语言一样。
2. Stream APi 整体的设计思路。
首先,我们得有一个数据源,比如一个 int[]{1,2,3}, 一个collection等。
然后对这个数据源,我们可以定义,我们需要做什么操作。
比较常用的操作就是, filter,map, distinct 等等。
注意,当前的阶段还只是定义操作,不做任何执行。为了方便理解,你可以把数据源理解为数据库,
而定义的操作则是数据库视图view。
最后,stream 定义好View之后,就有一个执行引擎,他负责分析 操作集合,哪些过程是可以在一个for循环一起做的,并叠加结果
而哪些过程是需要依赖前面的结果的。
stream 中有一个 stateful 和stateless 的概念,如果 几个操作可以同时做,那么这几个操作就是无状态的。比如filter,flat等等。
如果一个操作必须要等待前面的操作完成,那么他就是有状态,比如sort排序等。
执行完定义的操作之后,stream 有一个 结果收集器, 可以指定你想要的结果收集方式, 比如 toList, groupby, 或提供reduce函数,这个收集器
实现的非常强大和灵活。
3. 如何实现的?
对于一个 collection.stream().filter().map().sort().collect() java 8是如何实现的呢?
对于每一个操作 比如filter 会抽象成一个stage, stage相连接构成一个链式的流水线。
直白的想法就是流水线的开头,分别调用下一个流stage节点,并检查下一个流水线是否是短路操作(如Collect)
对于java 每个stage 有 begin, end, accept 操作。 begin可以做一些初始化工作,比如sort的begin函数可能初始化一个容器。
而sort 的end 操作可能是进行排序等。
4. 与函数编程的关系
设想让你自己用设计模式实现上述的设计思想,你绕不开的一个问题,就是 filter, map,sort 等方法中,如何能够接收用户提供的函数作为参数,
就像是传入了一个callback一样。
java8 提供了lambda 和Function编程包。 Function编程包基本上可以对现有任何的函数形式进行建模。
比如:有一个参数,一个返回,多个参数多个返回的,都可以抽象成Function对象
而lambda表达式,其实是和函数等价的,只不过lambda更加简洁,javac的类型推到可以正确的把lambda推导成Function类型。
5.性能
stream api 完全是可以用复杂一点的for循环来叠加所有的操作,
根据大神的测试报告,单核情况下,for循环的性能是最好的,但是由于stream 的并发架构,多核情况下,比for循环还要好。
其实,我觉得在大多数的场景下,我们都还不至于计较那些个毫秒的差距。
6. 使用案例
针对collection, map 的所有操作貌似都可以用stream api实现。
try everything using stream in your business
如果不能实现,就去看看stream reduce 的api。