内容简介:上一篇文章,咱们通过解答这个问题,让我们直接上维基百科吧:
上一篇文章,咱们通过 DiffUtil
来引出了函数式的那么一点点内容。今天的文章,将会重点聊一聊函数式编程所能给我们 开发模式 上的改变。
思想交融,Android中的函数式编程(1):DiffUtil体验
一、什么是函数式编程
解答这个问题,让我们直接上维基百科吧:
函数式编程(functional programming),是一种编程范式,它将计算机运算视为 函数运算 ,并且 避免使用程序状态 (也就是咱们上篇文章提到的stateless)以及 不可变对象 (上篇文章提到的immutable)。其中, λ演算 (lambda表达式)为该语言最重要的基础。而且,λ演算的函数可以接受函数当作输入(引数)和输出(传出值)(也就是Kotlin中所推崇的高阶函数)。
概念巴拉巴拉说了一大堆,总结一下也就是:
- 代码无状态
- 使用不可变对象
- Lambda表达式和高阶函数
接下来,咱们一一展开这些内容:
二、函数式编程的特点
2.1、无状态(stateless)
这个特性讲究的是: 函数不维护任何状态 。
咋理解呢?对于函数式编程来说,函数所做的,就是 接受输入 ,然后处理完 返回输出 。重点在于,函数执行完毕前,内部的任何变量是永远不会被函数外所改变的。也就是说, 参与函数执行的变量永远是局部变量!
在代码里就是这个样子:
// 非函数式,有状态(Stateful) // 这里有个成员变量,调这个全局函数变量++,这里面是有状态的,这个状态在外部。所以,如果是多线程的话,这里面的代码是不安全的。 class StatefulAddition{ var result = 0 fun addOneCount():Int{ result++ return result } } // 函数式,无状态(Stateless) class StatelessAddition{ fun addOneCount(one :Int): Int{ return one + 1 } } 复制代码
感受到二者在编码方式上的不同了吧。没感受到?那就好好感受一下子...
这里咱们想一想,函数式编程讲究这样的思想,有什么好处呢?
我们知道,因为状态的存在,在 并行执行 时引发bug的概率是非常高的,毕竟多线程操作成员变量的行为很常见(我们可以使用加锁的方式去解决问题),稍不留神就会被坑。所以 没有状态就没有伤害 (毕竟在这种思想下,代码的执行不包括中间状态的出现)。
2.2、不可变变量(immutable)
immutable这个概念需要好好感受。这个概念正好印证了Kotlin中 val
关键字的设计。我们千万不要单纯的把 val
和 Java 中 final
关键字“混为一谈”。(虽然好像它们就是一个东西)
val
定义一个不可变的变量,也就是说这个变量一但被声明将不能被再次赋值。这也就是immutable所推崇的意义(Kotlin中 val
就是 immutable
的具体实现)。
让我们上一段代码,感受一下:
// Mutable // 类中的成员变量都是以var声明的 data class MutableModel(var name: String) data class ImmutableModel(val name: String) val mutableModel = MutableModel("mdove") val newNameMutaleModel = mutableModel.apply { name = "new mdove" } // Immutable // 类中的成员变量都是以val声明的,意味着:想换个name,必须得重新new这个类 val immutableModel = ImmutableModel("mdove") val newNameMutableModel1 = ImmutableModel("new mdove") // data class 特有的复制变量的方式(就是一种快捷的new) val newNameMutableModel2 = immutableModel.copy("new mdove") 复制代码
OK,这就是immutable。还记不记得,我们在上篇文章中提到过:
因为DiffUtil设计本身就是对不同的集合对象进行diff。因此我们在update的时候,就必须要输入俩个不同的集合实例。
所以Immutable这个特性,完美的对应了Diff的特性。所以Immutable的特性在很多框架或者业务场景中非常非常的合适以及好用。这里先有一个关于此的印象,然后在随后的业务中慢慢去感受,慢慢感受~
2.3、高阶函数
在函数式编程中引入了高阶函数的概念,概念可能在Java中并不是很常见。咱们用一段代码来感受一下高阶函数在Kotlin中的应用,以及它在Java中的能找到的类似实现。
// 高阶函数 fun logString(mValue: String) { Log.d("mdove", mValue) } fun logList(list: MutableList<String>, func: (String) -> Unit) { list.forEach { func.invoke(it) } } // 直接把函数以参数的形式,传进去 logList(mutableListOf("111","222","333"),::logString) // 非高阶函数 interface LogString { fun invoke(string: String) } fun logList(list: MutableList<String>, logString: LogString) { list.forEach { logString.invoke(it) } } // 匿名内部类的方式执行 logList(mutableListOf("111", "222", "333"), object :LogString{ override fun invoke(string: String) { Log.d("mdove", string) } }) 复制代码
高阶函数的出现,让函数式编程变得异常的方便,极大的提高了我们的开发效率。现在已经入手Kotlin的小伙伴,肯定对Kotlin中“变化多端”的操作符搞的大呼“真香”了吧?
2.4、操作符
因为高阶函数的存在,Kotlin中存在很多效率爆炸的操作符,接下来让我们通过具体的操作符和Java中的实现进行对比。直接上代码,从代码中感受一切~~~
遍历一种类型的集合,然后转换成另种类型的集合
// Java实现 fun listLongToString(list: List<Long>): List<String> { val result= mutableListOf<String>() for (i in list.indices){ result.add(list[i].toString()) } return result } // Kotlin实现,map操作符 fun List<Long>.listLongToString(): List<String> { return this.map { it.toString() } } 复制代码
打平某种类型的集合
// Java实现 fun getAllNames(list: List<TestModel>): List<String> { val result = mutableListOf<String>() for (i in list.indices) { for (j in list[i].nameList.indices) { result.add(list[i].nameList[j]) } } return result } // Kotlin,flatMap操作符 fun List<TestModel>.getAllNames(): List<String> { return this.flatMap { it.nameList } } 复制代码
过滤掉所有为null的集合
// Java实现 fun filterNullOrEmpty(list:List<String?>):List<String>{ val result = mutableListOf<String>() for (i in list.indices){ if (!list[i].isNullOrEmpty()){ result.add(list[i]!!) } } return result } // Kotlin,filter操作符 fun List<String?>.filterNullOrEmpty:List<String>{ return this.filterNotNull().filterNot { it.isEmpty() } } 复制代码
最后整一个有趣的操作符:groupBy
listOf("123", "1", "2", "3", "12", "321", "21", "45", "1234", "5678").groupBy { it.length }.map { Log.d("mdove", "${it.key} - ${it.value}") } 复制代码
直接通过输出结果,来感受这个操作符的魅力吧:
2.5、表达式
最后想聊一聊表达式(Expression)这个特性,表达式随处可见。 val num = a + b;
这里的 a + b
就是一个表达式,它赋值给某个变量。这似乎很正常,但是有“不正常”的:
让我们来感受一下Kotlin中更为强大的表达式用法:
// 比较俩个数的大小,并输出大的。在Java中的实现可以是这样: fun sMax(a:Int,b:Int):Int{ var result=0 if(a>b){ result=a }else{ result=b } return result } // 可以在Kotlin中if-else是一个表达式,也就是说它可以赋值给变量,因此在Kotlin中的实现是这样的: fun eMax(a:Int,b:Int):Int{ return if(a>b) a else b } 复制代码
尾声
关于函数式的概念,我想文章已经写的足够清楚了。并且其中关于Java和Kotlin的代码对比,基本能够感受到函数式所带来的不一样的编程体验。
这里并非是推崇和安利函数式编程,更多的是一种融合。有些时候我们的确需要看看“外面的世界”,感受更大更有趣的编程世界~~
我是一个应届生,最近和朋友们维护了一个公众号,内容是我们在从应届生过渡到开发这一路所踩过的坑,以及我们一步步学习的记录,如果感兴趣的朋友可以关注一下,一同加油~
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 函数式编程之数组的函数式编程
- 函数式编程 – 函数式编程如何影响您的编码风格?
- 纯函数:函数式编程入门
- 深入理解 Java 函数式编程,第 1 部分: 函数式编程思想概论
- 编程范式 —— 函数式编程入门
- Kotlin 函数与函数式编程
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。