習慣使用kotlin高階函數

kotlin提供了高階函數這個概念,能夠在一些場景提升編碼效率java

1、什麼是高階函數bash

通俗的說和數學裏面的高階函數概念相似,也就是函數裏面的參數能夠是函數。固然返回值也能夠是函數。ide

2、kotlin高階函數使用場景分析函數

1.先看看平時使用比較多的內置高階函數 用kotlin寫view的onClickListenerui

tV.setOnClickListener {
            //doSomeThing
        }
複製代碼

裏面的lamba表達式就是一個函數編碼

不太形象?再看看集合裏面的filter、mapspa

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函數code

2.高階函數有什麼用cdn

就拿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, 2) { a: Int, b: Int ->
            a + b < 5
        }
複製代碼

這樣就省了個接口,後面分析實際是編譯器幫忙處理,其實仍是生成了接口

3、kotlin高階函數的實現

來看看kotlin編譯器是怎麼實現的吧 首先把上面那段kotlin代碼反編譯成java

kt:
   fun filter(a: Int, b: Int, canFilter: (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

image.png
這裏因爲我傳的是2個參數的lambda函數,因此調用的是Function2

那麼從這裏能得來上面結論:

a.高階函數所謂的能夠省略接口,其實只能省略只有一個方法的接口,由於function函數只有一個方法

b.上邊的fliter函數除了canFIlter(a,b)還能夠使用canFilter.invoke(a,b)調用。這個在須要對函數判空的時候頗有用。好比替換隻有一個方法的接口回調能夠callback?.invoke(a,b,c) , 由於callbck?(a,b,c)是不能編譯經過的。

c.雖然Functions.kt文件方法數是有限的,感受意味着lambda參數是有限的,最多22個參數,超過會編譯失敗。可是當真的超過期,會調用另一個FunctionN.kt

operator fun invoke(vararg args: Any?): R
複製代碼

不過若是誰寫的函數,直接傳參20多個還不封成對象或者builder,怕是腿都要被打斷.......

4、關於高階函數替換接口的討論

上面已經討論了,當接口只有一個方法時,確實能夠用高階函數代替,省略一個接口。

可是當接口有多個方法時,顯然不能直接替換。雖然也能夠把幾個函數包裝在一塊兒使用,可是仍是感受畫蛇添足。

多人並行開發的時候,好比一我的負責寫一個負責ui,一個負責使用ui處理業務邏輯。先把接口定好,接口方法文檔寫好,一目瞭然。這一方面仍是接口好不少,當只有簡單的一個方法時,用高階函數要方便一些。

相關文章
相關標籤/搜索