1. 程式人生 > >Kotlin系列之Lambda表示式完全解析

Kotlin系列之Lambda表示式完全解析

簡述: 今天帶來的Kotlin淺談系列的第六彈, 一起來聊下Kotlin中的lambda表示式。lambda表示式應該都不陌生,在Java8中引入的一個很重要的特性,將開發者從原來繁瑣的語法中解放出來,可是很遺憾的是隻有Java8版本才能使用。而Kotlin則彌補了這一問題,Kotlin中的lambda表示式與Java混合程式設計可以支援Java8以下的版本。那我們帶著以下幾個問題一起來看下Kotlin中lambda表示式。

  • 1、為什麼要使用Kotlin的lambda表示式(why)?
  • 2、如何去使用Kotlin的lambda表示式(how)?
  • 3、Kotlin的lambda表示式一般用在哪(where)?
  • 4、Kotlin的lambda表示式的作用域變數和變數捕獲
  • 5、Kotlin的lambda表示式的成員引用

一、為什麼要使用Kotlin的lambda表示式?

針對以上為什麼使用Kotlin中的lambda表示式的問題,我覺得有三點主要的原因。

  • 1、Kotlin的lambda表示式以更加簡潔易懂的語法實現功能,使開發者從原有冗餘囉嗦的語法宣告解放出來。可以使用函數語言程式設計中的過濾、對映、轉換等操作符處理集合資料,從而使你的程式碼更加接近函數語言程式設計的風格。
  • 2、Java8以下的版本不支援Lambda表示式,而Kotlin則相容與Java8以下版本有很好互操作性,非常適合Java8以下版本與Kotlin混合開發的模式。解決了Java8以下版本不能使用lambda表示式瓶頸。
  • 3、在Java8版本中使用Lambda表示式是有些限制的,它不是真正意義上支援閉包,而Kotlin中lambda才是真正意義的支援閉包實現。(關於這個問題為什麼下面會有闡述)

二、Kotlin的lambda表示式基本語法

1、lambda表示式分類

在Kotlin實際上可以把Lambda表示式分為兩個大類,一個是普通的lambda表示式,另一個則是帶接收者的lambda表示式(功能很強大,之後會有專門分析的部落格)。這兩種lambda在使用和使用場景也是有很大的不同. 先看下以下兩種lambda表示式的型別宣告:

針對帶接收者的Lambda表示式在Kotlin中標準庫函式中也是非常常見的比如with,apply標準函式的宣告。

@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}

@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

看到以上的lambda表示式的分類,你是不是想到之前的擴充套件函數了,有沒有想起之前這張圖?

是不是和我們之前部落格說普通函式和擴充套件函式類似。普通的Lambda表示式類似對應普通函式的宣告,而帶接收者的lambda表示式則類似對應擴充套件函式。擴充套件函式就是這種宣告接收者型別,然後使用接收者物件呼叫直接類似成員函式呼叫,實際內部是通過這個接收者物件例項直接訪問它的方法和屬性。

2、lambda基本語法

lambda的標準形式基本宣告滿足三個條件:

含有實際引數

含有函式體(儘管函式體為空,也得宣告出來)

以上內部必須被包含在花括號內部

以上是lambda表示式最標準的形式,可能這種標準形式在以後的開發中可能見到比較少,更多是更加的簡化形式,下面就是會介紹Lambda表示式簡化規則

3、lambda語法簡化轉換

以後開發中我們更多的是使用簡化版本的lambda表示式,因為看到標準的lambda表示式形式還是有些囉嗦,比如實參型別就可以省略,因為Kotlin這門語言支援根據上下文環境智慧推匯出型別,所以可以省略,摒棄囉嗦的語法,下面是lambda簡化規則。

注意:語法簡化是把雙刃劍,簡化固然不錯,使用簡單方便,但是不能濫用,也需要考慮到程式碼的可讀性.上圖中Lambda化簡成的最簡單形式用it這種,一般在多個Lambda巢狀的時候不建議使用,嚴重造成程式碼可讀性,到最後估計連開發者都不知道it指代什麼了。比如以下程式碼:

這是Kotlin庫中的joinToString擴充套件函式,最後一個引數是一個接收一個集合元素型別T的引數返回一個CharSequence型別的lambda表示式。

//joinToString內部宣告
public fun <T> Iterable<T>.joinToString(separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): String {
    return joinTo(StringBuilder(), separator, prefix, postfix, limit, truncated, transform).toString()
}


fun main(args: Array<String>) {
    val num = listOf(1, 2, 3)
    println(num.joinToString(separator = ",", prefix = "<", postfix = ">") {
        return@joinToString "index$it"
    })
}

我們可以看到joinToString的呼叫地方是使用了lambda表示式作為引數的簡化形式,將它從圓括號中提出來了。這個確實給呼叫帶來一點小疑惑,因為並沒有顯示錶明lambda表示式應用到哪裡,所以不熟悉內部實現的開發者很難理解。對於這種問題,Kotlin實際上給我們提供解決辦法,也就是我們之前部落格提到過的命名引數。使用命名引數後的程式碼

//joinToString內部宣告
public fun <T> Iterable<T>.joinToString(separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): String {
    return joinTo(StringBuilder(), separator, prefix, postfix, limit, truncated, transform).toString()
}
fun main(args: Array<String>) {
    val num = listOf(1, 2, 3)
    println(num.joinToString(separator = ",", prefix = "<", postfix = ">", transform = { "index$it" }))
}

4、lambda表示式的返回值

lambda表示式返回值總是返回函式體內部最後一行表示式的值

package com.mikyou.kotlin.lambda

fun main(args: Array<String>) {

    val isOddNumber = { number: Int ->
        println("number is $number")
        number % 2 == 1
    }

    println(isOddNumber.invoke(100))
}

將函式體內的兩個表示式互換位置後

package com.mikyou.kotlin.lambda

fun main(args: Array<String>) {

    val isOddNumber = { number: Int ->
        number % 2 == 1
        println("number is $number")
    }

    println(isOddNumber.invoke(100))
}

通過上面例子可以看出lambda表示式是返回函式體內最後一行表示式的值,由於println函式沒有返回值,所以預設打印出來的是Unit型別,那它內部原理是什麼呢?實際上是通過最後一行表示式返回值型別作為了invoke函式的返回值的型別,我們可以對比上述兩種寫法的反編譯成java的程式碼:

//互換位置之前的反編譯程式碼
package com.mikyou.kotlin.lambda;

import kotlin.jvm.internal.Lambda;

@kotlin.Metadata(mv = {1, 1, 10}, bv = {1, 0, 2}, k = 3, d1 = {"\000\016\n\000\n\002\020\013\n\000\n\002\020\b\n\000\020\000\032\0020\0012\006\020\002\032\0020\003H\n¢\006\002\b\004"}, d2 = {"<anonymous>", "", "number", "", "invoke"})
final class LambdaReturnValueKt$main$isOddNumber$1 extends Lambda implements kotlin.jvm.functions.Function1<Integer, Boolean> {
    public final boolean invoke(int number) {//此時invoke函式返回值的型別是boolean,對應了Kotlin中的Boolean
        String str = "number is " + number;
        System.out.println(str);
        return number % 2 == 1;
    }

    public static final 1INSTANCE =new 1();

    LambdaReturnValueKt$main$isOddNumber$1() {
        super(1);
    }
}

//互換位置之後的反編譯程式碼
package com.mikyou.kotlin.lambda;

import kotlin.jvm.internal.Lambda;

@kotlin.Metadata(mv = {1, 1, 10}, bv = {1, 0, 2}, k = 3, d1 = {"\000\016\n\000\n\002\020\002\n\000\n\002\020\b\n\000\020\000\032\0020\0012\006\020\002\032\0020\003H\n¢\006\002\b\004"}, d2 = {"<anonymous>", "", "number", "", "invoke"})
final class LambdaReturnValueKt$main$isOddNumber$1 extends Lambda implements kotlin.jvm.functions.Function1<Integer, kotlin.Unit> {
    public final void invoke(int number) {//此時invoke函式返回值的型別是void,對應了Kotlin中的Unit
        if (number % 2 != 1) {
        }
        String str = "number is " + number;
        System.out.println(str);
    }

    public static final 1INSTANCE =new 1();

    LambdaReturnValueKt$main$isOddNumber$1() {
        super(1);
    }
}

5、lambda表示式型別

Kotlin中提供了簡潔的語法去定義函式的型別.

() -> Unit//表示無引數無返回值的Lambda表示式型別

(T) -> Unit//表示接收一個T型別引數,無返回值的Lambda表示式型別

(T) -> R//表示接收一個T型別引數,返回一個R型別值的Lambda表示式型別

(T, P) -> R//表示接收一個T型別和P型別的引數,返回一個R型別值的Lambda表示式型別

(T, (P,Q) -> S) -> R//表示接收一個T型別引數和一個接收P、Q型別兩個引數並返回一個S型別的值的Lambda表示式型別引數,返回一個R型別值的Lambda表示式型別

上面幾種型別前面幾種應該好理解,估計有點難度是最後一種,最後一種實際上已經屬於高階函式的範疇。不過這裡說下個人看這種型別的一個方法有點像剝洋蔥一層一層往內層拆分,就是由外往裡看,然後做拆分,對於本身是一個Lambda表示式型別的,先暫時看做一個整體,這樣就可以確定最外層的Lambda型別,然後再用類似方法往內部拆分。

6、使用typealias關鍵字給Lambda型別命名

我們試想一個場景就是可能會用到多個lambda表示式,但是這些lambda表示式的型別很多相同,我們就很容易把所有相同一大串的Lambda型別重複宣告或者你的lambda型別宣告太長不利於閱讀。實際上不需要,對於Kotlin這門反對一切囉嗦語法的語言來說,它都給你提供一系列的解決辦法,讓你簡化程式碼的同時又不降低程式碼的可讀性。

fun main(args: Array<String>) {
    val oddNum:  (Int) -> Unit = {
        if (it % 2 == 1) {
            println(it)
        } else {
            println("is not a odd num")
        }
    }

    val evenNum:  (Int) -> Unit = {
        if (it % 2 == 0) {
            println(it)
        } else {
            println("is not a even num")
        }
    }

    oddNum.invoke(100)
    evenNum.invoke(100)
}

使用typealias關鍵字宣告(Int) -> Unit型別

package com.mikyou.kotlin.lambda

typealias NumPrint = (Int) -> Unit//注意:宣告的位置在函式外部,package內部

fun main(args: Array<String>) {
    val oddNum: NumPrint = {
        if (it % 2 == 1) {
            println(it)
        } else {
            println("is not a odd num")
        }
    }

    val evenNum: NumPrint = {
        if (it % 2 == 0) {
            println(it)
        } else {
            println("is not a even num")
        }
    }

    oddNum.invoke(100)
    evenNum.invoke(100)
}

三、Kotlin的lambda表示式經常使用的場景

  • 場景一: lambda表示式與集合一起使用,是最常見的場景,可以各種篩選、對映、變換操作符和對集合資料進行各種操作,非常靈活,相信使用過RxJava中的開發者已經體會到這種快感,沒錯Kotlin在語言層面,無需增加額外庫,就給你提供了支援函數語言程式設計API。
package com.mikyou.kotlin.lambda

fun main(args: Array<String>) {
    val nameList = listOf("Kotlin", "Java", "Python", "JavaScript", "Scala", "C", "C++", "Go", "Swift")
    nameList.filter {
        it.startsWith("K")
    }.map {
        "$it is a very good language"
    }.forEach {
        println(it)
    }

}


* 場景二: 替代原有匿名內部類,但是需要注意一點就是隻能替代含有單抽象方法的類。

    findViewById(R.id.submit).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ...
            }
        });

用kotlin lambda實現

findViewById(R.id.submit).setOnClickListener{
    ...
}
  • 場景三: 定義Kotlin擴充套件函式或者說需要把某個操作或函式當做值傳入的某個函式的時候。
fun Context.showDialog(content: String = "", negativeText: String = "取消", positiveText: String = "確定", isCancelable: Boolean = false, negativeAction: (() -> Unit)? = null, positiveAction: (() -> Unit)? = null) {
    AlertDialog.build(this)
            .setMessage(content)
            .setNegativeButton(negativeText) { _, _ ->
                negativeAction?.invoke()
            }
            .setPositiveButton(positiveText) { _, _ ->
                positiveAction?.invoke()
            }
            .setCancelable(isCancelable)
            .create()
            .show()
}

fun Context.toggleSpFalse(key: String, func: () -> Unit) {
    if (!getSpBoolean(key)) {
        saveSpBoolean(key, true)
        func()
    }
}

fun <T : Any> Observable<T>.subscribeKt(success: ((successData: T) -> Unit)? = null, failure: ((failureError: RespException?) -> Unit)? = null): Subscription? {
    return transformThread()
            .subscribe(object : SBRespHandler<T>() {
                override fun onSuccess(data: T) {
                    success?.invoke(data)
                }

                override fun onFailure(e: RespException?) {
                    failure?.invoke(e)
                }
            })
}

四、Kotlin的lambda表示式的作用域中訪問變數和變數捕獲

1、Kotlin和Java內部類或lambda訪問區域性變數的區別

  • 在Java中在函式內部定義一個匿名內部類或者lambda,內部類訪問的函式區域性變數必須需要final修飾,也就意味著在內部類內部或者lambda表示式的內部是無法去修改函式區域性變數的值。可以看一個很簡單的Android事件點選的例子
public class DemoActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_demo);
        final int count = 0;//需要使用final修飾
        findViewById(R.id.btn_click).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                System.out.println(count);//在匿名OnClickListener類內部訪問count必須要是final修飾
            }
        });
    }
}
  • 在Kotlin中在函式內部定義lambda或者內部類,既可以訪問final修飾的變數,也可以訪問非final修飾的變數,也就意味著在Lambda的內部是可以直接修改函式區域性變數的值。以上例子Kotlin實現

訪問final修飾的變數

class Demo2Activity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_demo2)
        val count = 0//宣告final
        btn_click.setOnClickListener {
            println(count)//訪問final修飾的變數這個是和Java是保持一致的。
        }
    }
}

訪問非final修飾的變數,並修改它的值

class Demo2Activity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_demo2)
        var count = 0//宣告非final型別
        btn_click.setOnClickListener {
            println(count++)//直接訪問和修改非final型別的變數
        }
    }
}

通過以上對比會發現Kotlin中使用lambda會比Java中使用lambda更靈活,訪問受到限制更少,這也就回答本部落格最開始說的一句話,Kotlin中的lambda表示式是真正意義上的支援閉包,而Java中的lambda則不是。Kotlin中的lambda表示式是怎麼做到這一點的呢?請接著看

2、Kotlin中lambda表示式的變數捕獲及其原理

  • 什麼是變數捕獲?

通過上述例子,我們知道在Kotlin中既能訪問final的變數也能訪問或修改非final的變數。原理是怎樣的呢?在此之前先丟擲一個高大上的概念叫做lambdab表示式的變數捕獲。實際上就是lambda表示式在其函式體內可以訪問外部的變數,我們就稱這些外部變數被lambda表示式給捕獲了。有了這個概念我們可以把上面的結論變得高大上一些:

第一在Java中lambda表示式只能捕獲final修飾的變數

第二在Kotlin中lambda表示式既能捕獲final修飾的變數也能訪問和修改非final的變數

  • 變數捕獲實現的原理

我們都知道函式的區域性變數生命週期是屬於這個函式的,當函式執行完畢,區域性變數也就是銷燬了,但是如果這個區域性變數被lambda捕獲了,那麼使用這個區域性變數的程式碼將會被儲存起來等待稍後再次執行,也就是被捕獲的區域性變數是可以延遲生命週期的,針對lambda表示式捕獲final修飾的區域性變數原理是區域性變數的值和使用這個值的lambda程式碼會被一起儲存起來;而針對於捕獲非final修飾的區域性變數原理是非final區域性變數會被一個特殊包裝器類包裝起來,這樣就可以通過包裝器類例項去修改這個非final的變數,那麼這個包裝器類例項引用是final的會和lambda程式碼一起儲存

以上第二條結論在Kotlin的語法層面來說是正確的,但是從真正的原理上來說是錯誤的,只不過是Kotlin在語法層面把這個遮蔽了而已,實質的原理lambda表示式還是隻能捕獲final修飾變數,而為什麼kotlin卻能做到修改非final的變數的值,實際上kotlin在語法層面做了一個橋接包裝,它把所謂的非final的變數用一個Ref包裝類包裝起來,然後外部保留著Ref包裝器的引用是final的,然後lambda會和這個final包裝器的引用一起儲存,隨後在lambda內部修改變數的值實際上是通過這個final的包裝器引用去修改的。

最後通過檢視Kotlin修改非final區域性變數的反編譯成的Java程式碼就是一目瞭然了

class Demo2Activity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_demo2)
        var count = 0//宣告非final型別
        btn_click.setOnClickListener {
            println(count++)//直接訪問和修改非final型別的變數
        }
    }
}
@Metadata(
   mv = {1, 1, 9},
   bv = {1, 0, 2},
   k = 1,
   d1 = {"\u0000\u0018\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\u0012\u0010\u0003\u001a\u00020\u00042\b\u0010\u0005\u001a\u0004\u0018\u00010\u0006H\u0014¨\u0006\u0007"},
   d2 = {"Lcom/shanbay/prettyui/prettyui/Demo2Activity;", "Landroid/support/v7/app/AppCompatActivity;", "()V", "onCreate", "", "savedInstanceState", "Landroid/os/Bundle;", "production sources for module app"}
)
public final class Demo2Activity extends AppCompatActivity {
   private HashMap _$_findViewCache;

   protected void onCreate(@Nullable Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      this.setContentView(2131361820);
      final IntRef count = new IntRef();//IntRef特殊的包裝器類的型別,final修飾的IntRef的count引用
      count.element = 0;//包裝器內部的非final變數element
      ((Button)this._$_findCachedViewById(id.btn_click)).setOnClickListener((OnClickListener)(new OnClickListener() {
         public final void onClick(View it) {
            int var2 = count.element++;//直接是通過IntRef的引用直接修改內部的非final變數的值,來達到語法層面的lambda直接修改非final區域性變數的值
            System.out.println(var2);
         }
      }));
   }

   public View _$_findCachedViewById(int var1) {
      if(this._$_findViewCache == null) {
         this._$_findViewCache = new HashMap();
      }

      View var2 = (View)this._$_findViewCache.get(Integer.valueOf(var1));
      if(var2 == null) {
         var2 = this.findViewById(var1);
         this._$_findViewCache.put(Integer.valueOf(var1), var2);
      }

      return var2;
   }

   public void _$_clearFindViewByIdCache() {
      if(this._$_findViewCache != null) {
         this._$_findViewCache.clear();
      }

   }
}

3、Kotlin中lambda表示式變數捕獲注意事項

注意: 對於Lambda表示式內部修改區域性變數的值,只會在這個Lambda表示式被執行的時候觸發。

五、Kotlin的lambda表示式的成員引用

1、為什麼要使用成員引用

我們知道在Lambda表示式可以直接把一個程式碼塊作為一個引數傳遞給函式,但是有沒有遇到過這樣一個場景就是我要傳遞過去的程式碼塊,已經是作為了一個命名函式存在了,此時你還需要重複寫一個程式碼塊傳遞過去嗎?肯定不是,Kotlin拒絕囉嗦重複的程式碼。所以只需要成員引用替代即可。

fun main(args: Array<String>) {
    val persons = listOf(Person(name = "Alice", age = 18), Person(name = "Mikyou", age = 20), Person(name = "Bob", age = 16))
    println(persons.maxBy({ p: Person -> p.age }))
}

可以替代為

fun main(args: Array<String>) {
    val persons = listOf(Person(name = "Alice", age = 18), Person(name = "Mikyou", age = 20), Person(name = "Bob", age = 16))
    println(persons.maxBy(Person::age))//成員引用的型別和maxBy傳入的lambda表示式型別一致
}

2、成員引用的基本語法

成員引用由類、雙冒號、成員三個部分組成

3、成員引用的使用場景

  • 成員引用最常見的使用方式就是類名+雙冒號+成員(屬性或函式)
fun main(args: Array<String>) {
    val persons = listOf(Person(name = "Alice", age = 18), Person(name = "Mikyou", age = 20), Person(name = "Bob", age = 16))
    println(persons.maxBy(Person::age))//成員引用的型別和maxBy傳入的lambda表示式型別一致
}
  • 省略類名直接引用頂層函式(之前部落格有專門分析)
package com.mikyou.kotlin.lambda

fun salute() = print("salute")

fun main(args: Array<String>) {
    run(::salute)
}
  • 成員引用用於擴充套件函式

fun Person.isChild() = age < 18

fun main(args: Array<String>){
    val isChild = Person::isChild
    println(isChild)
}

到這裡有關Kotlin lambda的基礎知識就基本淺談完畢了,下一篇會從Lambda實質原理和位元組碼方面分析,以及Lambda表示式使用時效能優化。

歡迎關注Kotlin開發者聯盟,這裡有最新Kotlin技術文章,每週會不定期翻譯一篇Kotlin國外技術文章。如果你也喜歡Kotlin,歡迎加入我們~~~

相關推薦

Kotlin系列Lambda表示式完全解析

簡述: 今天帶來的Kotlin淺談系列的第六彈, 一起來聊下Kotlin中的lambda表示式。lambda表示式應該都不陌生,在Java8中引入的一個很重要的特性,將開發者從原來繁瑣的語法中解放出來,可是很遺憾的是隻有Java8版本才能使用。而Kotlin則彌

Kotlin系列Lambda表示式(1)

今天開始後續的幾篇Kotlin的文章會介紹Kotlin中Lambda表示式相關的內容。 什麼是Lambda表示式 在Java8中引入了Lambda表示式,這是最令Java開發者激動和期待的一個功能。那究竟什麼是Lambda表示式呢? Lambd

Kotlin系列Lambda表示式(2)

上一篇文章講到了最基本的Lambda表示式,今天這篇文章繼續講Lambda表示式中的在作用域中訪問變數。 Java中的內部類訪問變數 當我們在函式內部使用匿名內部類時,我們可以在匿名內部類內使用函式的引數和函式內的區域性變數。當我們在使用Lamb

Kotlin系列Lambda表示式(3)

今天一起來看看Kotlin中與Lambda相關的成員引用的內容。 定義 先說說什麼是成員引用,這裡的引用指的就是變數引用,就相當於Java中的引用概念。成員的概念這裡包含了成員變數和成員方法。這都是很官方的的說法。說白了,就是類裡面的變數和函式。

JAVA8 Lambda表示式完全解析

JAVA8 新特性 在學習JAVA8 Lambda之前,必須先了解一下JAVA8中與Lambda相關的新特性,不然對於一些概念會感到比較陌生。 1、 介面的預設方法和靜態方法 Java 8允許我們給介面新增一個預設方法,用default修飾即可。預

Kotlin系列集合和函式式API完全解析-上篇

簡述: 今天帶來的是Kotlin淺談系列的第八講,這講我們一起來聊聊Kotlin這門語言對函數語言程式設計的支援。我們都知道在kotlin這門語言中函式榮升成為了一等公民,所以在支援函數語言程式設計的方面,Kotlin這門語言也是非常給力的,並且在Kotlin中

Java8新特性Lambda表示式解析及其常見用法

Lambda表示式是Java8更新的一大新特性,與同期更新的Stream是此版本的最大亮點。 “這是你從來沒有玩過的全新版本” —– 扎扎輝 -> 舉個栗子 : 建立一個執行緒 //old Thread thread1 = new Thread(

[Java]“語法糖”系列(二)Lambda表示式/匿名函式(Lambda Expression)

>什麼是Lambda表示式     簡短的說,Lambda表示式是一種用於取代匿名類,把函式行為表述為函數語言程式設計風格的一種匿名函式。     匿名類大家自然熟悉,上面那句話提到了“函式行為”,那麼什麼是函式行為? >函式行為     假設有這樣一個應用場

Kotlin開發三 kotlin中的lambda表示式

1 Lambda表示式定義 kotlin中lambda表示式定義如下: {param1:Type,param2:Type… -> ….} 例子 {x:Int,y:String -> y.length + x} 就是一個lambda表示式 在kotl

Python3lambda表示式和三元運算子

lambda表示式 lambda表示式,通常是在需要一個函式,但是又不想費神去命名一個函式的場合下使用,也就是指匿名函式。 lambda是一個表示式而不是一個語句,lambda用來編寫簡單的函式,不會再重複利用的函式。而def用來處理強大的任務。 lambda就是用來定義一個匿名函式的,如果

基礎 | Java8新特性Lambda表示式

Lambda表示式是Java8所引入的新特性之一,其基於函式式介面,以極大地減少程式碼冗餘,並提高程式碼的可讀性。 Lambda表示式的基本語法 參考答案: Java8中引入箭頭操作符(也叫Lambda操作符)將Lambda表示式拆分成左右兩部分: 左

Java8新特性Lambda表示式學習二

大家好,又來到超超部落格大本營啦!歡迎大家...... 上一章我們講解了Lambda表示式的基礎語法,引數列表、變數等知識點,接下來我們接續探究Lambda的表示式、以及其中的方法引用。 一、Lambda的表示式: (1)如果表示式只有一行,那麼可以直接寫(不需要{}); (2)

Java8新特性Lambda表示式學習一

       剛畢業入職新工作,在職崗位培訓時,老師在操作集合老使用Lambda表示式。這使一個之前完全沒有接觸過Lambda表示式的少年甚是苦惱,看不懂,閒餘時間決定搞一搞Lambda表示式到底是啥東西?底層原理怎麼實現的,接下來我將我的學習成果一起分享

(譯)Effective Kotlin系列遇到多個構造器引數要考慮使用Builder(二)

翻譯說明: 原標題: Effective Java in Kotlin, item 2: Consider a builder when faced with many constructor parameters 原文地址: https://blog.kotlin-academy.

(譯)Effective Kotlin系列考慮使用靜態工廠方法替代構造器(一)

翻譯說明: 原標題: Effective Java in Kotlin, item 1: Consider static factory methods instead of constructors 原文地址: https://blog.kotlin-academy.com/eff

python基礎lambda表示式

一. 在排序中的應用 例: >>> List=[{"name":"wan gang","age":22,"gender":"boy","score":583}, {"name":"zhang mei","age":21,"gender":"girl","score":53

Java8新特性lambda表示式

     在瞭解lambda表示式之前,必須先了解函數語言程式設計、函式式介面和default方法。在Java8出來之前,別的程式語言中已經有了函數語言程式設計這種概念,只不過後來沒落了,不過在最近幾年又火起來了。在Java8中大力提倡我們使用函數語言程式設計,並且更新了一些

(譯)Effective Kotlin系列探索高階函式中inline修飾符(三)

簡述: 不知道是否有小夥伴還記得我們之前的Effective Kotlin翻譯系列,之前一直忙於趕時髦研究Kotlin 1.3中的新特性。把此係列耽擱了,趕完時髦了還是得踏實探究本質和基礎,從今天開始我們將繼續探索Effective Kotlin系列,今天是Effective Kotlin第三講。 翻譯說明

[譯]Effective Kotlin系列使用Sequence來優化集合的操作(四)

簡述: 今天迎來了Effective Kotlin系列的第四篇文章: 使用Sequence序列來優化大集合的頻繁操作.關於Sequence這個主題應該大家都不陌生,我寫過幾篇有關它的文章,可以說得上很詳細了。如果你對它的使用不太熟悉,歡迎檢視下面幾篇有關文章: 淺談Kotlin中的Sequences原

[譯]Effective Kotlin系列考慮使用原始型別的陣列優化效能(五)

翻譯說明: 原標題: Effective Kotlin: Consider Arrays with primitives for performance critical processing 原文地址: blog.kotlin-academy.com/effective-k… 原文作者: Marcin