Android---Kotlin 学习012
函数式编程
我们一直在学习面向对象编程范式(范式即套路),另一个较为知名的编程范式是诞生于20世纪50年,基于抽象数学的 λ 演算发展而来的函数式编程,尽管函数式编程语言更常用在学术而非商业软件领域,但它的一些原则适用于任何编程语言。函数式编程范式主要依赖于高阶函数(以函数为参数或返回函数)返回的数据,这些高阶函数专用于处理各种集合,可方便地联合多个同类函数构建链式操作以创建复杂的计算行为。Kotlin 支持多种编程范式,所以你可以混用面向对象编程和函数式编程范式来解决手头的问题。
函数类别
一个函数式应用通常由三大类函数构成:变换 transform、过滤 filter、合并 combine。每类函数都针对集合数据类型设计,目标是产生一个最终结果。函数式编程用到的函数来生成都是可组合的,也就是说,你可以组合多个简单函数来构建复杂的计算行为。
变换
变换是函数式编程的第一大类函数,变换函数会遍历集合内容,用一个以值参形式传入的变换器函数,变换每一个元素,然后返回包含已修改元素的集合给链上的其他函数。
最常用的两个变换函数是 Map 和 flatMap。
?变换函数 Map
map 变换函数会遍历接收者集合,让变换器函数作用于集合里的各个元素,返回结果是包含已修改元素的集合,会作为链上下一个函数的输入。
可以看到,原始集合没有被修改,map 变换函数和你定义的变换器函数做完事情后,返回的是一个新集合,这样,变量就不用变来变去了。
事实上,函数式编程范式支持的设计理念就是不可变数据的副本在链上的函数间传递。
map 返回的集合中的元素个数和输入集合必须一样。不过,返回的新集合里的元素可以是不同类型的。
?变换函数 flatMap
flatMap 函数操作一个集合的集合,将其中多个集合中的元素合并后返回一个包含所有元素的单一集合。
过滤
过滤是函数式编程的第二大类函数,过滤函数接受一个 predicate 函数,用它按给定条件检查接收者集合里的元素并给出 true 或 false 的判断。如果 predicate 函数返回 true,受检元素就会添加到过滤函数返回的新集合里。如果 predicate 函数返回 false,那么受检元素就被移出新集合。
?过滤函数 filter
filter 过滤函数接受一个 predicate 函数,在 flatMap 遍历它的输入集合中的所有元素时,filter 函数会让 predicate 函数按过滤条件,将符合条件的元素都放入它返回的新集合里。最后,flatMap 会把变换器函数返回的子集合合并在一个新集合里。
案例:通过 filter 找素数
素数,除了 1 和它本身,不能被任何数整除的数。仅使用了几个简单函数,我们就解决了找素数这个比较复杂的问题,这就是函数式编程的独特魅力:每个函数做一点,组合起来就能干大事。
如果通过 java 代码来写,肯定要用到 for 循环,肯定没有这么简洁。?
合并
合并是函数式编程的第三大类函数,合并函数能将不同的集合合并成一个新集合,这和接收者是包含集合的集合 flatMap 函数不同。
?zip
zip 合并函数用来合并两个集合,返回一个包含键值对的新集合。
?fold
另一个可以用来合并值的合并类函数是 fold,这个合并函数接受一个初始累加器值,随后会根据匿名函数的结果更新。
示例:遍历一个集合,将每一个元素值乘以3,然后累加起来。
为什么要使用函数式编程
乍看之下,实现同样的任务,Java 版本和函数式版本的代码量差不多,但仔细分析一下,就能看出函数式版本的诸多优势。
?累加变量(employeeShirtSizes)都是隐式定义的;
?函数运算结果会自动赋值给累加变量,降低了代码出错的机会;
?执行新任务的函数很容易添加到函数链上,因为他们都兼容 Iterable 类型。
序列
List、Set、Map集合类型,这几个集合类型统称为及早集合(eager collection)。这些集合的任何一个实例在创建后,它要包含的元素都会被加入并允许你访问。对应及早集合,Kotlin 还有另外一类集合:惰性集合(lazy collection)类似于类的惰性初始化,惰性集合类型的性能表现优异,尤其是用于包含大量元素的集合时,因为集合元素是按需产生的。
Kotlin 有个内置惰性集合类型叫序列(Sequence),序列不会索引排序它的内容,也不记录元素数目。事实上,在使用一个序列时,序列里的值可能有无限多,因为某个数据源能产生无限多个元素。
generateSequence
针对某个序列,你可能会定义一个只要序列有新值产生就被调用一下的函数,这样的函数叫迭代器函数,要定义一个序列和它的迭代器,你可以使用 Kotlin 的序列构造函数 generateSequence,generateSequence 函数接受一个初始种子值作为序列的起步值,在用 generateSequence 定义的序列上调用一个函数时,generateSequence 函数会调用你指定的迭代器函数,决定下一个要产生的值。
示例:产生1000个素数
这么没有 1000个。如果要取 1000 个,就可以用到我们的 sequence
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!