【Kotlin 初学者】函数式编程

简介: 一、函数式编程概念1.1 面向函数编程(FOP) 在函数式编程(FP)中,一切皆是函数。FP是关于不变性和函数组合的一种编程范式。 函数式语言提倡在有限的几种关键数据结构(如list、set、map)上,运用函数的组合(高阶函数)操作,自底向上地来构建世界。Kotlin支持多种编程范式,所以你可以混用面向对象编程和函数式编程范式来解决手头的问题。

作者简介:CSDN博客专家、华为云·云享专家认证

系列专栏:Kotlin 初学者



一、函数式编程概念


1.1 面向函数编程(FOP)


       在函数式编程(FP)中,一切皆是函数。FP是关于不变性和函数组合的一种编程范式。


       函数式语言提倡在有限的几种关键数据结构(如list、set、map)上,运用函数的组合(高阶函数)操作,自底向上地来构建世界。Kotlin支持多种编程范式,所以你可以混用面向对象编程和函数式编程范式来解决手头的问题。


1.2 高阶函数


       一个函数的参数列表中存在函数类型的参数或是函数的返回值类型为函数类型,那么这个函数就叫做高阶函数。


1.3 为什么使用函数式编程


乍看之下,实现同样的任务,Java版本和函数式版本的代码量差不多,但仔细分析一下,就能看出函数式版本的诸多优势。


  • 累加变量(employeeShirtSizes)都是隐式定义的。


  • 函数运算结果会自动赋值给累加变量,降低了代码出错的机会。


  • 执行新任务的函数很容易添加到函数调用链上,因为他们都兼容lterable类型。


二、函数式编程类别


一个函数式应用通常由三大类函数构成:


  • 变换transform。


  • 过滤filter


  • 合并combine。


       每类函数都针对集合数据类型设计,目标是产生一个最终结果。函数式编程用到的函数生来都是可组合的,也就是说,你可以组合多个简单函数构建复杂的计算行为


2.1 变换transform


       变换是函数式编程的第一大类函数,变换函数会遍历集合内容,用一个以值参形式传入的变换器函数,变换每一个元素,然后返回包含已修改元素的集合给链上的其他函数。


最常用的两个变换函数是map和flatMap。


2.1.1 map


       map变换函数会遍历接收者集合,让变换器函数作用于集合里的各个元素,返回结果是包含已修改元素的集合,会作为链上下一个函数的输入。


       map返回的集合中的元素个数和输入集合必须一样,不过,返回的新集合里的元素可以是不同类型的。


fun main() {
    var citys = listOf("北京", "上海", "广州", "深圳")
    var chinaCitys = citys
        .map { citys -> "中国-$citys" }
        .map { china -> "$china,一线城市!" }
    //原始集合
    println(citys)
    //修改原始集合元素
    println(chinaCitys)
}

微信图片_20220525022112.png


可以看到,原始集合没有被修改,map变换函数和你定义的变换器函数做完事情后,返回的是一个新集合,这样,变量就不用变来变去了。


       事实上,函数式编程范式支持的设计理念就是不可变数据的副本在链上的函数间传递。


2.1.2 flatMap


       flatMap函数操作一个集合的集合,将其中多个集合中的元素合并后返回一个包含所有元素的单一集合。


    //一个集合的集合:List<List<String>>
    var cityslist = listOf(listOf("北京", "上海", "广州", "深圳"), listOf("合肥","杭州","成都"))
    //多个集合中的元素合并,返回一个新集合flatCity
    var flatCity = cityslist.flatMap { it }
    //原始集合
    println(cityslist)//[[北京, 上海, 广州, 深圳], [合肥, 杭州, 成都]]
    //合并后集合元素
    println(flatCity)//[北京, 上海, 广州, 深圳, 合肥, 杭州, 成都]


2.2 过滤filter


       过滤是函数式编程的第二大类函数,过滤函数接受一个predicate函数,用它按给定条件检查接收者集合里的元素并给出true或false的判定。


  • 如果predicate函数返回true,受检元素就会添加到过滤函数返回的新集合里。


  • 如果predicate函数返回false,那么受检元素就被移出新集合


       可以理解为按条件筛选元素。


fun main() {
    var number = listOf(1,3,5,7,12,19,21)
    //过滤元素大于15的元素,并添加到新集合
    var newNumber = number.filter { it>15 }
    //原始数据
    println(number)//[1, 3, 5, 7, 12, 19, 21]
    //过滤后
    println(newNumber)//[19, 21]
}


filter+flatMap


       对一个集合的集合先合并再过滤。


    //flatMap+filter
    var numberList = listOf(
        listOf(1, 2, 3, 4, 5),
        listOf(6, 7, 8, 9, 10), listOf(11, 12, 13, 14, 15)
    )
    //先合并,后过滤
    var newNumberList = numberList.flatMap { it.filter { it % 2 == 0 } }
    println(numberList)//[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]]
    println(newNumberList)//[2, 4, 6, 8, 10, 12, 14]


2.3 合并combine


       合并是函数式编程的第三大类函数,合并函数能将不同的集合合并成一个新集合,这和接收者是包含集合的集合的flatMap函数不同。


2.3.1 zip


       zip合并函数来合并两个集合,返回一个包含键值对的新集合。


1.fun main() {
    val name = listOf("变换","过滤","合并")
    val age = listOf(7, 25, 36)
    val list = name.zip(age)
    println(list)//[(变换, 7), (过滤, 25), (合并, 36)]
    val map = list.toMap()
    println(map)//{变换=7, 过滤=25, 合并=36}
    println(map["过滤"])//25
}


2.3.2 fold


       fold合并函数接受一个初始累加器值,随后会根据匿名函数的结果更新。


fun main() {
    //初始值为10,将每个元素乘以2相加
    var total = listOf(4, 8, 12).fold(10) { total, number ->
        println("Total:$total")
        total + (number * 2)
    }
    println(total)
}


微信图片_20220525022456.png


三、序列


  • 及早集合(eager collection):List、Set、Map集合的任何一个实例在创建后,它要包含的元素都会被加入并允许你访问。


  • 惰性集合〈lazy collection):类似于类的惰性初始化,惰性集合类型的性能表现优异,尤其是用于包含大量元素的集合时,因为集合元素是按需产生的


       Kotlin有个内置惰性集合类型叫序列(Sequence),序列不会索引排序它的内容,也不记录元素数目,事实上,在使用一个序列时,序列里的值可能有无限多,因为某个数据源能产生无限多个元素。


generateSequence


       generateSequence函数接受一个初始种子值作为序列的起步值,在用generateSequence定义的序列上调用一个函数时,generateSequence函数会调用你指定的迭代器函数,决定下一个要产生的值。


fun main() {
    //在1-3000的范围内产生1000个能同时整除2和整除7的数
    val list = (1..3000).toList().filter { it % 2 == 0 && it % 7 == 0 }.take(1000)
    println(list.size)//214
    //[14, 28, 42, 56, 70, 84, 98, ...2954, 2968, 2982, 2996]
    println(list)
    //使用序列,取满足条件的1000个为止
    val slist = generateSequence(1,
        { num ->
            num + 1
        })
        .filter { it % 2 == 0 && it % 7 == 0 }
        .take(1000)
        .toList()
    println(slist.size)//1000
    //[14, 28, 42, 56, 70, 84, 98, ...13958, 13972, 13986, 14000]
    println(slist)
}




相关文章
|
算法 Java Scala
用 Kotlin 的函数式编程 替代 GOF 设计模式
用 Kotlin 的函数式编程 替代 GOF 设计模式 函数式编程(FP) 《Kotlin极简教程》正式上架: 点击这里 > 去京东商城购买阅读 点击这里 > 去天猫商城购买阅读 非常感谢您亲爱的读者,大家请多支持!!!有任何问题,欢迎随时与我交流~ 值就是函数,函数就是值。
1535 0
Kotlin闭包(支持函数式编程不再是梦想)
一、闭包 闭包目前非常火,因为闭包的出现,现在支持函数式编程就不再是梦想了。 二、什么是闭包 1.函数的运行环境 2.
2050 0
在 Java 9 的JShell中 跟Kotlin 的REPL中尽情体验函数式编程乐趣吧
Java 9 JShell : 螢幕快照 2017-09-25 22.58.02.png jshell> List alphabet = List.
1183 0
kotlin极简教程 高阶函数 函数式编程章节节选
kotlin极简教程 高阶函数 函数式编程章节节选 KotlinChina编程社区 微博 《Kotlin极简教程》正式上架: 点击这里 > 去京东商城购买阅读 点击这里 > 去天猫商城购买阅读 非常感谢 if (boy) { 帅气英俊潇洒} else { 魔鬼身材天使脸蛋美丽动人女神气质} 的您。
1054 0
《Kotlin 程序设计》第六章 Kotlin 函数式编程(FP)
第六章 Kotlin 函数式编程(FP) 正式上架:《Kotlin极简教程》Official on shelves: Kotlin Programming minimalist tutorial 京东JD:https://item.jd.com/12181725.html 天猫Tmall:https://detail.tmall.com/item.htm?id=558540170670 1. 函数式编程概述 从本质上来说, 程序就是一系列有序执行的指令集合。
1222 0
《Kotlin极简教程》第六章 Kotlin函数式编程(FP)
Kotlin对函数式编程的实现恰到好处。 正式上架:《Kotlin极简教程》Official on shelves: Kotlin Programming minimalist tutorial 京东JD:https://item.
997 0
|
1月前
|
安全 Java Android开发
使用Kotlin进行Android应用开发:高效、简洁与乐趣并存
【6月更文挑战第1天】Kotlin,JetBrains开发的静态类型语言,正日益成为Android开发首选。它与Java兼容,提供简洁、安全的语法,如空安全、扩展函数和Lambda表达式,提升开发效率和代码可读性。Kotlin在Android开发中的优势包括提高开发速度、降低学习曲线及强大的社区支持。实践中,数据类简化对象创建,扩展函数增强SDK,Lambda表达式简化回调处理,协程优化异步操作。掌握Kotlin对Android开发者极具价值。
|
2月前
|
存储 安全 Android开发
构建高效的Android应用:Kotlin与Jetpack的结合
【5月更文挑战第31天】 在移动开发的世界中,Android 平台因其开放性和广泛的用户基础而备受开发者青睐。随着技术的进步和用户需求的不断升级,开发一个高效、流畅且易于维护的 Android 应用变得愈发重要。本文将探讨如何通过结合现代编程语言 Kotlin 和 Android Jetpack 组件来提升 Android 应用的性能和可维护性。我们将深入分析 Kotlin 语言的优势,探索 Jetpack 组件的核心功能,并通过实例演示如何在实际项目中应用这些技术。
|
20天前
|
安全 Java 编译器
Android面试题之Java 泛型和Kotlin泛型
**Java泛型是JDK5引入的特性,用于编译时类型检查和安全。泛型擦除会在运行时移除类型参数,用Object或边界类型替换。这导致几个限制:不能直接创建泛型实例,不能使用instanceof,泛型数组与协变冲突,以及在静态上下文中的限制。通配符如<?>用于增强灵活性,<? extends T>只读,<? super T>只写。面试题涉及泛型原理和擦除机制。
20 3
Android面试题之Java 泛型和Kotlin泛型