Kotlin與java8的SAM轉(zhuǎn)換對比(進(jìn)階)
什么是sam 轉(zhuǎn)換
Single Abstract Method 實際上這是java8中提出的概念,你就把他理解為是 一個方法的接口 的就可以了
看一下我們每天都在使用的線程池
ExecutorService executorService= Executors.newScheduledThreadPool(3); executorService.execute(new Runnable() { @Override public void run() { System.out.println("hello world"); } });
用下面的java8中的lambda 來寫 也是可以的。
xecutorService.execute(()->System.out.println("hello world"));
所以說 這兩種寫法是 等價 的。 但是這里要強(qiáng)調(diào)的是 java中的lambda是沒有類型的,所以他必須需要一個接口來接受他。
kotlin中的sam
val executorService: ExecutorService = Executors.newScheduledThreadPool(3) //kotlin中的 匿名內(nèi)部類的標(biāo)準(zhǔn)寫法 executorService.submit(object :Runnable{ override fun run() { System.out.println("hello world") } })
kotlin中的lambda 這里可以這么寫
executorService.submit { System.out.println("hello world") }
這里要注意的是 java的lambda是沒有類型的,但是kotlin的lambda有類型 。
上文中的例子 這個kotlin的lambda的類型就是 ()->Unit 是一個沒有參數(shù)也沒有返回值的類型
對于kotlin中的lambda來說,仔細(xì)看上面的圖 就可以知道。
這里實際上是創(chuàng)建了一個runnable 并且在這個runnable里面 包裝了一下lambda,并不是直接轉(zhuǎn)換的 。
//kotlin中 匿名內(nèi)部類 還可以這么寫 executorService.submit(Runnable { println("hello world") })
上面的代碼 我們再解釋一下 ,kotlin的編譯器 再遇到上面的代碼的時候 實際上 是 幫我們生成了 一個函數(shù)
這個函數(shù)的作用就是接收一個 lambda表達(dá)式 然后幫我們生成對應(yīng)的代碼
kotlin中sam 轉(zhuǎn)換的坑
java中的lambda是假的,只是一個sam而已。 kotlin的lambda是真的,只不過他還支持sam。是支持sam轉(zhuǎn)換的。
下面定義一個kotlin的接口 以及kotlin的方法
interface Invokable{ fun invoke() } fun submit(invokable: Invokable){ invokable.invoke() }
然后我們看看調(diào)用:
看看報錯的原因
Type mismatch: inferred type is () -> Unit but Invokable was expected
提示我們 這里 是需要一個invokable,但是給了一個lambda ,不符合要求,所以編譯不能通過。
這個可以理解吧,前面已經(jīng)講過了。
fun submit2(block:()->Unit){ block.invoke() }
如果我們定義一個這樣的函數(shù) 那顯然就是可以的了。就可以直接使用lambda了。
當(dāng)然如果每次這么寫,函數(shù)參數(shù)也比較難寫,所以我們干脆 就起個別名
typealias Funtionx = () -> Unit fun submit2(block: Funtionx) { block.invoke() }
另外就是在kotlin中使用sam轉(zhuǎn)換的時候 一定要小心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); } }
現(xiàn)在 kotlin代碼 我們要add 一個監(jiān)聽
val eventManager = EventManager() eventManager.addOnEventListener { println("onEvent$it") }
lambda寫起來很方便,但是你要小心了,你這么寫的話 你是沒辦法remove的。 你仔細(xì)想一想,上面的寫法 等于是
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") } })
這個創(chuàng)建匿名對象的過程 被編譯器做了,你是接觸不到這個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") } }
這種寫法雖然丑是丑了一點(diǎn),但是言簡意賅,不會出歧義 也不會出錯。
到此這篇關(guān)于Kotlin與java8的SAM轉(zhuǎn)換對比的文章就介紹到這了,更多相關(guān)Kotlin與java8的SAM轉(zhuǎn)換 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot2.2.2集成dubbo的實現(xiàn)方法
這篇文章主要介紹了springboot2.2.2集成dubbo的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01Spring中AOP的切點(diǎn)、通知、切點(diǎn)表達(dá)式及知識要點(diǎn)整理
這篇文章主要介紹了Spring中AOP的切點(diǎn)、通知、切點(diǎn)表達(dá)式及知識要點(diǎn)整理,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03Spring Boot @Scheduled定時任務(wù)代碼實例解析
這篇文章主要介紹了Spring Boot @Scheduled定時任務(wù)代碼實例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-06-06使用maven一步一步構(gòu)建spring mvc項目(圖文詳解)
這篇文章主要介紹了詳解使用maven一步一步構(gòu)建spring mvc項目,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-09-09Java8內(nèi)存模型PermGen Metaspace實例解析
這篇文章主要介紹了Java8內(nèi)存模型PermGen Metaspace實例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03