1. 前言
我們知道兜畸,在程序中,通常情況下苫耸。一個(gè)類會(huì)有自己的方法(函數(shù))以及屬性,這些方法代表了該類的特性或者說(shuō)具有的能力儡陨。今天我們一起來(lái)研究一下 kotlin中的函數(shù)褪子。
2.如何聲明一個(gè)函數(shù)
在 kotlin 中,我們通過(guò)關(guān)鍵字 fun 來(lái)聲明一個(gè)函數(shù)
fun multiply(x:Int,y:Int):Int{
... //代碼塊
return x*y
}
如上面的代碼所示:我們定義了函數(shù)multiply()并指定其返回類型為 Int 類型骗村。
3.Lambda表達(dá)式
3.1 Lambda表達(dá)式介紹
從Java8 開(kāi)始嫌褪,Lambda表達(dá)式在 Lambda表達(dá)式,在其他的編程語(yǔ)言中(例如:Scala
語(yǔ)言),這種表達(dá)式是語(yǔ)法糖中的一種,在 kotlin 中胚股,也支持這種語(yǔ)法,它允許把函數(shù)作為一個(gè)方法的參數(shù)笼痛,可以使代碼變的更加簡(jiǎn)潔緊湊。
Lambda
表達(dá)式的本質(zhì)其實(shí)是匿名函數(shù)
琅拌,因?yàn)樵谄涞讓訉?shí)現(xiàn)中還是通過(guò)匿名函數(shù)
來(lái)實(shí)現(xiàn)的缨伊。但是我們?cè)谟玫臅r(shí)候不必關(guān)心起底層實(shí)現(xiàn)。不過(guò)Lambda
的出現(xiàn)確實(shí)是減少了代碼量的編寫(xiě)进宝,同時(shí)也是代碼變得更加簡(jiǎn)潔明了刻坊。
3.2 Java 8 Lambda 表達(dá)式
3.2.1 語(yǔ)法:
(parameters) -> expression
或
(parameters) ->{ statements; }
3.2.2 特征
可選類型聲明:不需要聲明參數(shù)類型,編譯器可以統(tǒng)一識(shí)別參數(shù)值党晋。
可選的參數(shù)圓括號(hào):一個(gè)參數(shù)無(wú)需定義圓括號(hào)谭胚,但多個(gè)參數(shù)需要定義圓括號(hào)徐块。
可選的大括號(hào):如果主體包含了一個(gè)語(yǔ)句,就不需要使用大括號(hào)灾而。
可選的返回關(guān)鍵字:如果主體只有一個(gè)表達(dá)式返回值則編譯器會(huì)自動(dòng)返回值胡控,大括號(hào)需要指定明表達(dá)式返回了一個(gè)數(shù)值。
3.2.3 代碼如下:
// 1. 不需要參數(shù),返回值為 5
() -> 5
// 2. 接收一個(gè)參數(shù)(數(shù)字類型),返回其2倍的值
x -> 2 * x
// 3. 接受2個(gè)參數(shù)(數(shù)字),并返回他們的差值
(x, y) -> x – y
// 4. 接收2個(gè)int型整數(shù),返回他們的和
(int x, int y) -> x + y
// 5. 接受一個(gè) string 對(duì)象,并在控制臺(tái)打印,不返回任何值(看起來(lái)像是返回void)
(String s) -> System.out.print(s)
從上面可以看出绰疤,代碼簡(jiǎn)潔了不少铜犬。
我們?cè)賮?lái)看一個(gè)例子,在java中假如要計(jì)算兩個(gè)數(shù)的和轻庆,則代碼如下:
import java.util.function.BiFunction;
public class helloword {
public static void main(String[] args) {
BiFunction<Integer,Integer,Integer> sum=(Integer x, Integer y) ->{
return x+y;
};
System.out.println("sum(3, 4) = " + sum.apply(3, 4));
}
}
運(yùn)行結(jié)果如下:
但是癣猾,在 java 8 以下版本,并不支持 Lambda 表達(dá)式余爆,而這個(gè)時(shí)候.kotlin 完美的兼容了 java 8 以下版本對(duì) lamdba 表達(dá)式的支持纷宇,并且能夠進(jìn)行混合開(kāi)發(fā)。
3.3 kotlin Lamdba 表達(dá)式
好蛾方,我們?cè)賮?lái)看看 Android 中 kotlin 的使用,Kotlin語(yǔ)言中
3.3.1 Lamdab 表達(dá)式 的聲明:
lambda表達(dá)式的完整語(yǔ)法如下:
{ params -> expressions }
params表示參數(shù)列表像捶,expressions表示具體實(shí)現(xiàn),可以是單行語(yǔ)句桩砰,也可以是多行語(yǔ)句拓春。
Lamdba 表達(dá)式的值為大括號(hào)最后一行的值。
3.3,2 Lamdba 表達(dá)式的類型表示:
() ->unit 無(wú)參亚隅,返回值為Unit
(Int)-> Int 傳入整型硼莽,返回一個(gè)整型
(String,(String)->String)->Boolean 傳入字符串,Lamdba 表達(dá)式煮纵,返回 Boolean
3.3.3 Lamdba 表達(dá)式的調(diào)用:
- 使用 () 進(jìn)行調(diào)用懂鸵,相當(dāng)于invoke()
3.3.4 Lamdba 表達(dá)式的簡(jiǎn)化:
args.forEach(){ println(it) } // 如果函數(shù)的最后一個(gè)參數(shù)是lamdba 表達(dá)式,則可以將lamdba 放在括號(hào)外面
args.forEach{ println(it) } // 如果函數(shù)參數(shù)只有一個(gè)lamdba表達(dá)式,則調(diào)用時(shí)小括號(hào)可以省略行疏。
args.forEach(::print) //入?yún)⒋夜猓祷刂蹬c形參一致的函數(shù)可以用函數(shù)引用的方式作為實(shí)參傳入。
上述同樣的功能酿联,kotlin 語(yǔ)言的實(shí)現(xiàn)如下:
- 自定義函數(shù)來(lái)實(shí)現(xiàn):
fun main(args: Array<String>) {
val result=sum(3,4)
println(result)
}
fun sum(arg1:Int,arg2:Int)=arg1+arg2
- 使用 Lamdba 表達(dá)式實(shí)現(xiàn):
fun main(args: Array<String>) {
println(result(3, 4))
}
val result = { arg1: Int, arg2: Int ->
println("$arg1+$arg2=${arg1 + arg2}")
arg1 + arg2
}
我們?cè)賮?lái)看個(gè)例子终息,要求:遍歷kotlin 中main函數(shù)的參數(shù),
- 示例代碼:Android 中最常見(jiàn)的點(diǎn)擊事件
tv_toLogin.setOnClickListener(object:View.OnClickListener{
override fun onClick(v: View?) {
Toast.makeText(this,"onClick",Toast.LENGTH_SHORT).show()
}
})
- 使用 Lambda 表達(dá)式的點(diǎn)擊事件
tv_toLogin.setOnClickListener({
Toast.makeText(this,"onClick",Toast.LENGTH_SHORT).show()
})
怎么樣贞让?有沒(méi)有感覺(jué) lamdba 表達(dá)式使用起來(lái)既簡(jiǎn)潔又優(yōu)雅采幌。
4. 高階函數(shù)
4.1 什么是高階函數(shù)
高階函數(shù)就是以另一個(gè)函數(shù)作為參數(shù)或返回值的函數(shù),Kotlin 可以以 lambda 或參數(shù)引用作為參數(shù)或返回值震桶,所以,任何以 lambda 或函數(shù)引用作為參數(shù)或返回值的都是高階函數(shù)征绎。
4.2 常見(jiàn)的高階函數(shù)
4.2.1 forEach()函數(shù)
fun main(args: Array<String>) {
val list= listOf(1,2,3,4,5,6,7,8)
val newList=ArrayList<Int>()
list.forEach{
val newElement=it *2+3
newList.add(newElement)
}
newList.forEach(::println)
}
運(yùn)行結(jié)果如下:
4.2.2 :map()函數(shù)
map: 接受一個(gè)lambda表達(dá)式蹲姐,并且有返回值磨取,形成一個(gè)新的list,實(shí)現(xiàn)對(duì)集合中的元素進(jìn)行修改
好,我們通過(guò)高階函數(shù) map 來(lái)實(shí)現(xiàn)如上的效果:
fun main(args: Array<String>) {
val list= listOf(1,2,3,4,5,6,7,8)
val newList=list.map {
it*2+3
}
println(newList)
}
運(yùn)行結(jié)果如下:
以上代碼中通過(guò)高階函數(shù) map 實(shí)現(xiàn)了對(duì)集合中每個(gè)元素乘以2再加3的操作柴墩,不用去遍歷集合中每個(gè)元素忙厌,是不是簡(jiǎn)單了許多。
4.2.3 flatMap()函數(shù)
flatMap是map和flat兩個(gè)函數(shù)的“復(fù)合邏輯江咳,可以將集合中的數(shù)據(jù)進(jìn)行合并成一個(gè)集合逢净。
示例代碼如下:
fun main(args: Array<String>) {
val list= listOf(
1..20,
21..30,
31..100
)
val flatList=list.flatMap {
it.map {
"NO.$it"
}
}
flatList.forEach{
println(it)
}
}
運(yùn)行結(jié)果如下: 將集合中數(shù)字從1~100打印輸出,每個(gè)數(shù)字前標(biāo)有“NO.”
4.2.4 filter()函數(shù)
傳入Lambda 表達(dá)式為 true 是歼指,保留該元素爹土;使用filter對(duì)集合進(jìn)行按條件過(guò)濾
fun main(args: Array<String>) {
val list= listOf(1,2,3,4,5,6,7,8,9)
val result=list.filter {
it%2==0
}
println(result)
}
運(yùn)行結(jié)果如下:
4.3 kotlin 中的 特殊函數(shù)
4.3.1 run()函數(shù)
該函數(shù)實(shí)際上可以說(shuō)是let和with兩個(gè)函數(shù)的結(jié)合體,run函數(shù)接收一個(gè)lambda函數(shù)為參數(shù)踩身,以閉包形式返回胀茵,返回值為最后一行的值或者指定的return的表達(dá)式。
示例代碼如下:
fun main(args: Array<String>) {
FunKotlin().myFun()
run {
FunKotlin().myFun()
}
run {
println("kotlin")
}
}
class FunKotlin{
fun myFun():String{
println("開(kāi)始執(zhí)行myFun()函數(shù)")
return "kotlin 中的特殊函數(shù)"
}
}
運(yùn)行結(jié)果如下:
在上面的代碼中挟阻,我們定義了myFun()函數(shù)并通過(guò)run() 進(jìn)行調(diào)用琼娘,調(diào)用的結(jié)果即為myFun()的結(jié)果。
run() 源碼如下:
/**
* Calls the specified function [block] and returns its result.
*/
@kotlin.internal.InlineOnly
public inline fun <R> run(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
如代碼所示:我們傳入block()參數(shù)附鸽,最終返回了block() 的執(zhí)行結(jié)果脱拼。
4.3.2 apply()函數(shù)
源碼如下:
/**
* Calls the specified function [block] with `this` value as its receiver and returns `this` value.
*/
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
如代碼所示:我們傳入 block() 函數(shù),先是調(diào)用了block()函數(shù)坷备,然后返回當(dāng)前的調(diào)用者對(duì)象this熄浓,也就是說(shuō)先執(zhí)行完block()代碼塊邏輯后,再次返回當(dāng)前的調(diào)用者對(duì)象击你。
示例代碼如下:
fun main(args: Array<String>) {
testApply()
}
fun testApply(){
val list= mutableListOf<String>()
list.add("A")
list.add("B")
list.add("C")
list.add("D")
list.add("E")
println("普通寫(xiě)法:list=${list}")
val applyList=mutableListOf<String>().apply {
add("A")
add("B")
add("C")
add("D")
add("E")
println("使用apply 函數(shù)寫(xiě)法 this=${this}")
}
}
運(yùn)行結(jié)果如下:
如代碼所示:我們的需求是創(chuàng)建一個(gè)集合并向其中添加元素"A"玉组,“B”,"C",“D”丁侄,“E”,然后打印出該集合惯雳,相比普通寫(xiě)法,使用apply() 函數(shù)顯然簡(jiǎn)潔了許多鸿摇。
4.3.3 let() 函數(shù)
let擴(kuò)展函數(shù)的實(shí)際上是一個(gè)作用域函數(shù)石景,當(dāng)你需要去定義一個(gè)變量在一個(gè)特定的作用域范圍內(nèi),let函數(shù)的是一個(gè)不錯(cuò)的選擇拙吉;let函數(shù)另一個(gè)作用就是可以避免寫(xiě)一些判斷null的操作
源碼如下:
/**
* Calls the specified function [block] with `this` value as its argument and returns its result.
*/
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
如代碼所示潮孽,我們重點(diǎn)看最后一行return block(this),就是說(shuō)把當(dāng)前調(diào)用對(duì)象作為參數(shù)傳入block()代碼塊中筷黔。
示例代碼如下:我們以Android中在適配器 adapter 中進(jìn)行網(wǎng)絡(luò)圖片的加載往史。
context?.let {
Glide.with(it).load(item.envelopePic).crossFade().into(helper.getView<ImageView>(R.id.iv_envelopePic))
}
在上面的代碼中,it 指代的即是 context佛舱,意為上下文椎例。</pre>
4.3.4 also()函數(shù)
源碼如下:
/**
* Calls the specified function [block] with `this` value as its argument and returns `this` value.
*/
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block(this)
return this
}
看最后兩行代碼挨决,先是執(zhí)行了block(this),隨后返回this订歪,即當(dāng)前的調(diào)用者對(duì)象脖祈。
示例代碼如下:
fun testAlsoFun() {
val a = "ABC".also {
println(it) //輸出:ABC
}
println(a) //輸出:ABC
a.let {
println(it) //輸出:ABC
}
}
fun main(args: Array<String>) {
testAlsoFun()
}
在上面的代碼中,字符串“ABC”調(diào)用了also()刷晋,會(huì)打印出調(diào)用者 “ABC”.
4.3.5 with() 函數(shù)
源碼如下:
/**
* Calls the specified function [block] with the given [receiver] as its receiver and returns its result.
*/
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}
我們看到with()函數(shù)傳入了一個(gè)接收者對(duì)象receiver盖高,然后使用該對(duì) 象receiver去調(diào)用傳入的Lambda代碼塊receiver.block()。
- 示例代碼在 Android中我們初始化一個(gè)控件并給其賦值眼虱,Java 語(yǔ)言實(shí)現(xiàn)如下:
TextView text=(TextView)findViewById(R.id.tv_text)
text.setText("哈哈哈")
text.setTextSize(23)
- kotlin 語(yǔ)言實(shí)現(xiàn)如下:
with(tv_text){
text="哈哈哈"
textSize=23
}
在上面的代碼中喻奥,實(shí)現(xiàn)的功能是一樣的,但是顯然 kotlin 語(yǔ)言更加的簡(jiǎn)潔蒙幻。