2017-05-19 90 views
10

單挑:我正在寫內存中的一些內容,所以我可能會有一些不正確的概念。Kotlin內聯函數比Java匿名類更便宜嗎?


Java有能力編寫一個匿名函數。當你有某種事件的監聽器接口時,這很有用。舉個例子:

button.setOnClickListener(new View.OnClickListener(View v) { 
    @Override 
    public void onClick(View v) { 
     // handle the action here 
    } 
}); 

匿名監聽器將被編譯爲一個名爲像OnClickListener$1.class類。這是Java語言的基礎設計決定。一切都是一個對象,甚至是匿名函數。

當您想要編寫功能更強大的代碼庫時,這會成爲問題。大量的匿名類創建了大量的類數,這在受限平臺(如Android)中可能會遇到問題。

從源代碼的角度來看,Kotlin函數更爲頭等。我的問題是,Kotlin是否比Java對匿名類更有效地將這些函數編譯爲字節碼,還是會遇到與Java中的大類類相同的問題?

感謝,

回答

9

簡短的回答是,Kotlin內聯函數相當便宜。

當內聯函數調用被編譯時,傳遞給調用的lambda表達式被內聯到函數體中,該函數體在內核中依次內聯在調用站點上。這允許編譯器不爲lambda體生成任何其他類或方法。

Compilation of an inline function

一個the slides約科特林通過@yole構建編譯。 不幸的是,我發現只有in Russian的記錄。其他幻燈片也有一些興趣,您可以在那裏找到更多關於非內聯lambda的信息。

通常,使用內聯函數和lambda表達式的Kotlin代碼的運行速度要快於使用lambdas或Streams的相同Java代碼。所有的代碼綁定都是在編譯時完成的,並且沒有虛擬方法調用的運行時間開銷,也沒有增加方法計數,這對Android來說很重要。

過度內聯的缺點是代碼大小的增長:內聯函數體的字節代碼的公共部分實際上在呼叫站點被複制。此外,內聯會使調試變得複雜,因爲代碼的行號和調用堆棧將與源文件中的內容不同。雖然IDE支持可以在這裏幫助。

我會建議你自己嘗試內聯函數:你可以很容易地inspect the resulting bytecode;當然,還要對性能至關重要的特定用例做一些基準測試。

+0

嘿,我只是想說深深的迴應感謝。這正是我所期待的。 – Brad

+0

@Brad不客氣,很高興我能提供幫助。 – hotkey

+0

謝謝先生,我明白了。 –

1

科特林有inline關鍵字。如果你使用這個關鍵字,它不僅可以內聯函數,而且可以將lambda體看作僅僅是一個嵌套的作用域級別,這樣你就可以從中得到return

例(直接從文檔)

fun foo() { 
    inlineFunction { 
     return // OK: the lambda is inlined 
    } 
} 

檢查出文檔的更多:

https://kotlinlang.org/docs/reference/inline-functions.html

編輯:

澄清你對性能準確的問題,這是來自文檔的第一段:

使用高階函數會施加一定的運行時間懲罰:每個函數都是一個對象,它捕獲一個閉包,即在函數體中訪問的那些變量。內存分配(對於函數對象和類)和虛擬調用都會引入運行時開銷。

但似乎在很多情況下,這種開銷可以通過內聯lambda表達式來消除。

所以,據我所知,它會內聯函數,並消除任何本來會施加的開銷。

但是,這似乎只適用於您聲明爲inline的函數。

+0

這不是我真正想問的,但謝謝。如果你將一個內聯函數傳遞給一個更高階的函數,它會在編譯的字節碼中創建多個函數是? – Brad

+0

@Brad編輯答案迴應您的關注 – hasen