擁抱kotlin之如何習慣使用kotlin高階函式
前言
kotlin提供了高階函式這個概念,可以在一些場景提高編碼效率
一、什麼是高階函式
通俗的說和數學裡面的高階函式概念類似,也就是函式裡面的引數可以是函式。當然返回值也可以是函式。
二、kotlin高階函式使用場景分析
1.先看看平時使用比較多的內建高階函式
用kotlin寫view的onClickListener
tV.setOnClickListener { //doSomeThing }
裡面的lamba表示式就是一個函式
不太形象?再看看集合裡面的filter、map
listOf(1,2,3) .filter { it > 2 } .map { it + 5 } /** * Returns a list containing only elements matching the given [predicate]. */ public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> { return filterTo(ArrayList<T>(),predicate) }
filter、map的引數都是一個lambda函式
2.高階函式有什麼用
就拿filter函式來說,比如實現一個過濾的邏輯,判斷是符合的
若classA 和classB都需要呼叫這個函式,那麼函式就需要相容這兩種情況
fun filter(): Boolean { if (classA) { return true } else if (classB) { return false } return false }
if else無可厚非,但是如果後面有classC classD...都需要考慮呢,這顯然違背了開閉原則。那麼自然是要面向抽象而不是具體,當然就是抽象類或者介面。
若用java的方式去實現,會變成這樣
interface IJudge { fun canFilter(): Boolean } class ClassA : IJudge { override fun canFilter(): Boolean { return true } } class ClassB : IJudge { override fun canFilter(): Boolean { return false } } fun filter(a:Int,b:Int,jugde: IJudge): Boolean { //加一些邏輯 return jugde.canFilter() }
這個是硬傷,面向抽象就得加這麼介面,然後多寫一些程式碼。
若用高階函式實現
fun filter(a: Int,b: Int,canFilter: (a:Int,b:Int) -> Boolean): Boolean { //加一些邏輯 return canFilter(a,b) } //呼叫方1 filter(1,2) { a: Int,b: Int -> a * b > 10 } //呼叫方2 filter(1,b: Int -> a + b < 5 }
這樣就省了個介面,後面分析實際是編譯器幫忙處理,其實還是生成了介面
三、kotlin高階函式的實現
來看看kotlin編譯器是怎麼實現的吧
首先把上面那段kotlin程式碼反編譯成java
kt: fun filter(a: Int,b:Int) -> Boolean): Boolean { //加一些邏輯 return canFilter(a,b) } java: public final boolean filter(int a,int b,@NotNull Function2 canFilter) { Intrinsics.checkParameterIsNotNull(canFilter,"canFilter"); canFilter.invoke(a,b); return (Boolean)canFilter.invoke(a,b); }
實際上是kt內建的 Functions.kt
這裡由於我傳的是2個引數的lambda函式,所以呼叫的是Function2
那麼從這裡能得來上面結論:
a.高階函式所謂的可以省略介面,其實只能省略只有一個方法的介面,因為function函式只有一個方法
b.上邊的fliter函式除了canFIlter(a,b)還可以使用canFilter.invoke(a,b)呼叫。這個在需要對函式判空的時候很有用。比如替換隻有一個方法的介面回撥可以callback?.invoke(a,b,c) , 因為callbck?(a,c)是不能編譯通過的。
c.雖然Functions.kt檔案方法數是有限的,感覺意味著lambda引數是有限的,最多22個引數,超過會編譯失敗。但是當真的超過時,會呼叫另外一個FunctionN.kt
operator fun invoke(vararg args: Any?): R
不過如果誰寫的函式,直接傳參20多個還不封成物件或者builder,怕是腿都要被打斷.......
四、關於高階函式替換介面的討論
上面已經討論了,當介面只有一個方法時,確實可以用高階函式代替,省略一個介面。
但是當介面有多個方法時,顯然不能直接替換。雖然也可以把幾個函式包裝在一起使用,但是還是感覺多此一舉。
多人並行開發的時候,比如一個人負責寫一個負責ui,一個負責使用ui處理業務邏輯。先把介面定好,介面方法文件寫好,一目瞭然。這一方面還是介面好很多,當只有簡單的一個方法時,用高階函式要方便一些。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對我們的支援。