内容简介:上一篇文章,咱们通过解答这个问题,让我们直接上维基百科吧:
上一篇文章,咱们通过 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 函数与函数式编程
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Writing Apache Modules with Perl and C
Lincoln Stein、Doug MacEachern / O'Reilly Media, Inc. / 1999-03 / USD 39.95
Apache is the most popular Web server on the Internet because it is free, reliable, and extensible. The availability of the source code and the modular design of Apache makes it possible to extend Web......一起来看看 《Writing Apache Modules with Perl and C》 这本书的介绍吧!