最近入职一个有趣的年轻同事,提交了大量大量的代码。翻开git记录一看,原来是用了非常多的java8的语法特性,重构了代码。用的最多的,就是map、flatMap之类的。

但是其他小伙伴不愿意了,虽然有的人感觉代码变的容易懂了,但有更多的人感觉代码变的很晦涩。
那感觉就像是:脱了裤子放屁,多此一举。

这些函数的作用域,根据级别,我觉得可以分为三类。简直是无所不在。

不要过分使用
我也不知道这些函数是从什么时候流行起来的,但它们与函数编程的关系肯定是非常密切的。好像是2004年的Scala开始的。

没什么神奇的,它们全部是语法糖,作用是让你的程序更简洁。你要是想,完全可以用多一点的代码去实现。不要为了炫技刻意去使用,物极必反,用不好的话,产生的效果会是非常负面的。比如java,它并不是一门函数编程语言,那么lambda就只是一种辅助;而你用java那一套去写Lisp代码的话,也只会不伦不类。

但语言还是要融合的,因为潮流就是这样。不去看他们背后的设计,我们仅从api的语义表象,横向看一下它们所表达的东西。

我们首先看一下其中的共性(注意:逻辑共性,并不适合所有场景),然后拿几个典型的实现,看一下在这个星球上,程序员们的表演。

这些抽象的概念
这些函数的作用对象,据说是一种称之为流的东西。那流到底是一种什么东西呢?请原谅我用一些不专业的话去解释。

不论是在语言层面还是分布式数据结构上,它其实是一个简单的数组。它有时候真的是一个简单的数组,有时候是存在于多台机器的分布式数组。在下文中,我们统称为数组流。

我们简单分为两类。

语言层面的:比如Java的Stream
分布式层面的:比如Spark的RDD
它们都有以下几个比较重要的点。

函数可以作为参数
C语言当然是没问题的,可以把函数作为指针传入。但在不久之前,在Java中,这还得绕着弯子去实现(使用java概念中的Class去模拟函数,你会见到很多Func1、Func0这样奇怪的java类)。

函数作参数,是使得代码变得简洁的一个必要条件。我们通常的编程方法,大多是顺序执行一些操作。

array = new Array()array = func1(array)if(func2(array)){    array = func3(array)}array = func4(array)

而如果函数能够当参数,我就能够尽量的将操作平铺。最终,还是要翻译成上面的语句进行执行的。

array = new Array()array.stream().map(func1).filter(func2).flatMap(func3).sorted(func4)...

编程模式完全变了,函数也有了语义。

sequential & parallel

如果我们的数组流太大,对于单机来说,就有顺序处理和并行处理两种方式。

通常,可以通过parallel函数进入并行处理模式。对于大多数本地操作,开了并行不见得一定会快。
java中使用ForkJoin那一套,线程的速度,你知道的…

而对于分布式数据流来说,本来就是并行的,这种参数意义就不大了。

函数种类
一般作用在数据流上的函数,会分为两类。

转换。Transformation动作。Action

转换,典型的特点就是lazy。
只有action执行的时候,才会真正参与运算。所以,你可以认为这些转换动作是一套被缓冲的操作。典型的函数如:map、flatMap等。它们就像烤串一样被串在一起,等着被撸。

动作。真正触发代码的运行,上面的一系列转换,也会像开了闸的洪水一样,一泻而下。典型的如reduce函数,就是这种。

以上的描述也不尽然,比如python的map,执行后就可以输出结果。这让人很没面子啊。

map & reduce
谈到map和reduce,大家就不约而同的想到了hadoop。然而,它不仅仅是大数据中的概念。

对于它俩的概念,我们仅做下面两行介绍。

map
将传入的函数依次作用到序列的每个元素,并把结果作为新的数组流返回。

reduce
reduce类似于一个递归的概念。最终会归约成一个值。看看这个公式:)

reduce([p1,p2,p3,p4],fn) = reduce([fn(p2,p4),fn(p1,p3)])

具体还是看谷歌的经典论文吧。

《MapReduce: Simplified Data
Processing on Large Clusters》

https://ai.google/research/pubs/pub62

你能访问么?:)

map & flatMap
这两个函数经常被使用。它们有如下区别:

map
把数组流中的每一个值,使用所提供的函数执行一遍,一一对应。得到元素个数相同的数组流。

flatMap
flat是扁平的意思。它把数组流中的每一个值,使用所提供的函数执行一遍,一一对应。得到元素相同的数组流。只不过,里面的元素也是一个子数组流。把这些子数组合并成一个数组以后,元素个数大概率会和原数组流的个数不同。

程序员们的表演
java8种的Stream
java8开始,加入了一个新的抽象,一个称之为流的东西:Stream。配合lambda语法,可以使代码变的特别的清爽、干净(有木有发现都快成了Scala了)。

一个非常好的向导:
https://stackify.com/streams-guide-java-8/

Spark的RDD操作
spark的核心数据模型就是RDD,是一个有向无环图。它代表一个不可变、可分区、其内元素可并行计算的集合。
它是分布式的,但我们可以看下一个WordCount的例子。

JavaRDD<String> textFile = sc.textFile("hdfs://...");JavaPairRDD<String, Integer> counts = textFile    .flatMap(s -> Arrays.asList(s.split(" ")).iterator())    .mapToPair(word -> new Tuple2<>(word, 1))    .reduceByKey((a, b) -> a + b);counts.saveAsTextFile("hdfs://...");

多么熟悉的Api啊,你一定在Hadoop里见过。

Flink 的 DataStream
Flink程序是执行分布式集合转换(例如,filtering, mapping, updating state, joining, grouping, defining windows, aggregating)的常规程序。Flink中的DataStream程序是实现在数据流上的transformation。

我们同样看一下它的一段代码。

DataStream<Tuple2<String, Integer>> counts =// split up the lines in pairs (2-tuples) containing: (word,1)text.flatMap(new Tokenizer())// group by the tuple field "0" and sum up tuple field "1".keyBy(0).sum(1);kafka stream的操作

kafka已经变成了一个分布式的流式计算平台。他抽象出一个KStream和KTable,与Spark的RDD类似,也有类似的操作。

KStream可以看作是KTable的更新日志(changlog),数据流中的每一个记录对应数据库中的每一次更新。

我们来看下它的一段代码。

KTable<String, Long> wordCounts = textLines.flatMapValues(value -> Arrays.asList(value.toLowerCase().split("\\W+"))).groupBy((key, value) -> value).count();wordCounts.toStream().to("streams-wordcount-output", Produced.with(stringSerde, longSerde));RxJava

RxJava是一个基于观察者模式的异步任务框架,经常看到会被用到Android开发中(服务端采用的也越来越多)。

RxJava再语言层面进行了一些创新,有一部分忠实的信徒。

语言层面的lambda
当然,对Haskell这种天生的函数编程语言来说,是自带光环的。但其他的一些语言,包括脚本语言,编译性语言,也吸收了这些经验。

它们统称为lambda。

Python
作为最流行的脚本语言,python同样也有它的lambda语法。最基本的map、reduce、filter等函数同样是存在的。

JavaScript
js也不能拉下,比如Array.prototype.*()等。它该有的,也都有了。

End
另外还有很多很多,就不一一罗列了。话说,这些函数可以申请专利么?我很喜欢,虽然我很少用。

©著作权归作者所有:来自51CTO博客作者mb5fed6ec4336ce的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 演示部分数组的排序,合并/交差并补等
  2. 快乐学习Pandas入门篇:Pandas基础
  3. C语言学习笔记 第三天
  4. PHP高级编程函数的返回值和闭包与作用域
  5. 数组的排序
  6. 数据结构与算法—队列(搞懂最常用数据结构之一)
  7. 数据结构与算法—栈详解(看完面试考试再也不怕了)
  8. php学习笔记(20个常用的字符串函数)
  9. 字符串函数

随机推荐

  1. add study URL
  2. Simulate android behaviors on win32
  3. Android录音下————AudioRecord源码分
  4. 在Android上编译OSG[3.0.2 ]
  5. 在Android中使用ExecutorService、Execut
  6. dumpsys cpuinfo
  7. Android Studio 之 View组件常用属性及其
  8. In FontFamilyFont, unable to find attr
  9. 新浪微博Oauth2.0授权认证及SDK、API的使
  10. 【Android】Activity知识点