Kotlin與java8的SAM轉換對比(進階)

什麼是sam 轉換

Single Abstract Method 實際上這是java8中提出的概念,你就把他理解爲是一個方法的接口的就能夠了java

看一下咱們天天都在使用的線程池bash

ExecutorService executorService= Executors.newScheduledThreadPool(3);

        executorService.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello world");
            }
        });
複製代碼

用下面的java8中的lambda 來寫 也是能夠的。ide

executorService.execute(()->System.out.println("hello world"));

複製代碼

因此說 這兩種寫法是等價的。 可是這裏要強調的是 java中的lambda是沒有類型的,因此他必須須要一個接口來接受他。函數

kotlin中的sam

val executorService: ExecutorService = Executors.newScheduledThreadPool(3)
    //kotlin中的 匿名內部類的標準寫法
    executorService.submit(object :Runnable{
        override fun run() {
            System.out.println("hello world")
        }

    })
    

複製代碼

kotlin中的lambda 這裏能夠這麼寫spa

executorService.submit { System.out.println("hello world") }

複製代碼

這裏要注意的是 java的lambda是沒有類型的,可是kotlin的lambda有類型線程

上文中的例子 這個kotlin的lambda的類型就是 ()->Unit 是一個沒有參數也沒有返回值的類型3d

對於kotlin中的lambda來講,仔細看上面的圖 就能夠知道。code

這裏其實是建立了一個runnable 而且在這個runnable裏面包裝了一下lambda,並非直接轉換的cdn

//kotlin中 匿名內部類 還能夠這麼寫
    executorService.submit(Runnable { println("hello world") })

複製代碼

上面的代碼 咱們再解釋一下 ,kotlin的編譯器 再遇到上面的代碼的時候 實際上 是幫咱們生成了 一個函數對象

這個函數的做用就是接收一個 lambda表達式 而後幫咱們生成對應的代碼

kotlin中sam 轉換的坑

java中的lambda是假的,只是一個sam而已。 kotlin的lambda是真的,只不過他還支持sam。是支持sam轉換的。

下面定義一個kotlin的接口 以及kotlin的方法

interface Invokable{
    fun invoke()
}


fun submit(invokable: Invokable){
    invokable.invoke()
}

複製代碼

而後咱們看看調用:

看看報錯的緣由

Type mismatch: inferred type is () -> Unit but Invokable was expected

提示咱們 這裏 是須要一個invokable,可是給了一個lambda ,不符合要求,因此編譯不能經過。

這個能夠理解吧,前面已經講過了。

fun submit2(block:()->Unit){
    block.invoke()
}

複製代碼

若是咱們定義一個這樣的函數 那顯然就是能夠的了。就能夠直接使用lambda了。

固然若是每次這麼寫,函數參數也比較難寫,因此咱們乾脆 就起個別名

typealias Funtionx = () -> Unit

fun submit2(block: Funtionx) {
    block.invoke()
}

複製代碼

另外就是在kotlin中使用sam轉換的時候 必定要當心remove的寫法,例如:

咱們定義一個簡單的event類:

public class EventManager {
    interface OnEventListener {
        void onEvent(int event);
    }

    private List<OnEventListener> onEventListeners=new ArrayList<OnEventListener>();

    public void addOnEventListener(OnEventListener listener){
        onEventListeners.add(listener);
    }

    public void removeEventListener(OnEventListener listener){
        onEventListeners.remove(listener);
    }


}

複製代碼

如今 kotlin代碼 咱們要add 一個監聽

val eventManager = EventManager()
    eventManager.addOnEventListener {
        println("onEvent$it")
    }
複製代碼

lambda寫起來很方便,可是你要當心了,你這麼寫的話 你是沒辦法remove的。 你仔細想想,上面的寫法 等因而

eventManager.addOnEventListener(object : EventManager.OnEventListener {
        override fun onEvent(event: Int) {
            {
                println("onEvent$event")
            }()
        }
    })
複製代碼

也等因而

eventManager.addOnEventListener(object : EventManager.OnEventListener {
        override fun onEvent(event: Int) {
            println("onEvent$event")
        }
    })
複製代碼

這個建立匿名對象的過程 被編譯器作了,你是接觸不到這個object的。

因此天然也就沒辦法去remove了。

遇到這種須要remove的狀況 咱們就能夠用以下寫法:

val onEvent = EventManager.OnEventListener {
        println("onEvent$it")

    }

    eventManager.addOnEventListener(onEvent)
    eventManager.removeEventListener(onEvent)

複製代碼

或者

val onEvent2 = object : EventManager.OnEventListener {
        override fun onEvent(event: Int) {
            println("onEvent$event")
        }

    }

複製代碼

這種寫法雖然醜是醜了一點,可是言簡意賅,不會出歧義 也不會出錯。

相關文章
相關標籤/搜索