什麼是sam 轉換 Single Abstract Method 實際上這是java8中提出的概念,你就把他理解為是一個方法的介面的就可以了 看一下我們每天都在使用的線程池 ExecutorService executorService= Executors.newScheduledThreadPo ...
什麼是sam 轉換
Single Abstract Method 實際上這是java8中提出的概念,你就把他理解為是一個方法的介面的就可以了
看一下我們每天都在使用的線程池
ExecutorService executorService= Executors.newScheduledThreadPool(3); executorService.execute(new Runnable() { @Override public void run() { System.out.println("hello world"); } });
用下麵的java8中的lambda 來寫 也是可以的。
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 這裡可以這麼寫
executorService.submit { System.out.println("hello world") }
這裡要註意的是 java的lambda是沒有類型的,但是kotlin的lambda有類型。
上文中的例子 這個kotlin的lambda的類型就是 ()->Unit 是一個沒有參數也沒有返回值的類型
對於kotlin中的lambda來說,仔細看上面的圖 就可以知道。
這裡實際上是創建了一個runnable 並且在這個runnable裡面包裝了一下lambda,並不是直接轉換的。
//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") } }
這種寫法雖然醜是醜了一點,但是言簡意賅,不會出歧義 也不會出錯。
“大清亡於閉關鎖國,學習技術需要交流和資料”。 在這裡我給大家準備了很多的學習資料免費獲取,包括但不限於java進階學習資料、技術乾貨、大廠面試題系列、技術動向、職業生涯等一切有關程式員的分享.
java進階方法筆記,學習資料,面試題,電子書籍免費領取,讓你成為java大神,追到自己的女神,走向人生巔峰