上一篇文章,我們經過DiffUtil
來引出了函數式的那麼一點點內容。今天的文章,將會重點聊一聊函數式編程所能給咱們開發模式上的改變。編程
思想交融,Android中的函數式編程(1):DiffUtil體驗安全
解答這個問題,讓咱們直接上維基百科吧:多線程
函數式編程(functional programming),是一種編程範式,它將計算機運算視爲函數運算,而且避免使用程序狀態(也就是我們上篇文章提到的stateless)以及不可變對象(上篇文章提到的immutable)。其中,λ演算(lambda表達式)爲該語言最重要的基礎。並且,λ演算的函數能夠接受函數看成輸入(引數)和輸出(傳出值)(也就是Kotlin中所推崇的高階函數)。app
概念巴拉巴拉說了一大堆,總結一下也就是:框架
接下來,我們一一展開這些內容:less
這個特性講究的是:函數不維護任何狀態。ide
咋理解呢?對於函數式編程來講,函數所作的,就是接受輸入,而後處理完返回輸出。重點在於,函數執行完畢前,內部的任何變量是永遠不會被函數外所改變的。也就是說,參與函數執行的變量永遠是局部變量!函數式編程
在代碼裏就是這個樣子:函數
// 非函數式,有狀態(Stateful)
// 這裏有個成員變量,調這個全局函數變量++,這裏面是有狀態的,這個狀態在外部。因此,若是是多線程的話,這裏面的代碼是不安全的。
class StatefulAddition{
var result = 0
fun addOneCount():Int{
result++
return result
}
}
// 函數式,無狀態(Stateless)
class StatelessAddition{
fun addOneCount(one :Int): Int{
return one + 1
}
}
複製代碼
感覺到兩者在編碼方式上的不一樣了吧。沒感覺到?那就好好感覺一會兒...post
這裏我們想想,函數式編程講究這樣的思想,有什麼好處呢?
咱們知道,由於狀態的存在,在並行執行時引起bug的機率是很是高的,畢竟多線程操做成員變量的行爲很常見(咱們可使用加鎖的方式去解決問題),稍不留神就會被坑。因此沒有狀態就沒有傷害(畢竟在這種思想下,代碼的執行不包括中間狀態的出現)。
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的特性在不少框架或者業務場景中很是很是的合適以及好用。這裏先有一個關於此的印象,而後在隨後的業務中慢慢去感覺,慢慢感覺~
在函數式編程中引入了高階函數的概念,概念可能在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中「變化無窮」的操做符搞的大呼「真香」了吧?
由於高階函數的存在,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}")
}
複製代碼
直接經過輸出結果,來感覺這個操做符的魅力吧:
最後想聊一聊表達式(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的代碼對比,基本可以感覺到函數式所帶來的不同的編程體驗。
這裏並不是是推崇和安利函數式編程,更多的是一種融合。有些時候咱們的確須要看看「外面的世界」,感覺更大更有趣的編程世界~~