引用:使用**
inline
**修飾符標記一個函數,在函數被使用的時候編譯器並不會生成函數調用的代碼markdown
當一個函數被聲明爲inline
時,它的函數體是內聯的——換句話說,函數體會被直接替換到函數被調用的地方,而不是被正常調用。函數
inline fun <T> synchronized(lock: Lock, action: () -> T): T {
lock.lock()
try {
return action()
}
finally {
lock.unlock()
}
}
fun foo(l: Lock) {
println("Before sync")
synchronized(l) {
println("Action")
}
println("After sync")
}
複製代碼
上述代碼在轉換成Java代碼時,inline
修飾的方法會自動添加到對應的方法中性能
public static final void foo(@NotNull Lock l) {
String var1 = "Before sync";
System.out.println(var1);
l.lock();
try {
String var3 = "Action";
System.out.println(var3);
Unit var8 = Unit.INSTANCE;
} finally {
l.unlock();
}
var1 = "After sync";
System.out.println(var1);
}
複製代碼
注意:lambda表達式和synchronized函數的實現都被內聯了。由lambda生成的字節碼稱爲了函數調用者定義的一部分,而不是被包含在一個實現了函數接口的匿名類中。ui
在調用內聯函數的時候也能夠傳遞函數類型的變量做爲參數:spa
class LockOwner(val lock: Lock) {
fun runUnderLock(body: () -> Unit) {
// 傳遞一個函數類型的變量做爲參數,而不是一個lambda
synchronized(lock, body)
}
}
複製代碼
這種狀況下,lambda的代碼在內聯函數被調用點是不可用的,所以並不會被內聯。 只有synchronized的函數體別內聯了,lambda纔會被正常調用。code
若是在兩個不一樣的位置使用同一個內聯函數,可是用的是不一樣的lambda,那麼內聯函數會在每個被調用的位置被分別內聯。orm
內聯函數的代碼會被拷貝到使用它的兩個不一樣爲孩子,並把不一樣的lambda替換到其中。對象
大部分標準庫中的集合函數都帶有lambda參數。相比於使用標準庫函數,直接實現這些操做不是更高效嗎?接口
data class PersonNew(val name: String = "", val age: Int = 0)
val people = listOf(PersonNew("Alice", 29), PersonNew("Bob", 31))
fun filterSetByLambdaTest() {
println(people.filter { it.age < 30 })
}
// 輸出結果
[Person(name=Alice, age=29)]
複製代碼
fun filterSetByManualTest() {
val result = mutableListOf<PersonNew>()
for (person in people) {
if (person.age < 30) result.add(person)
}
println(result)
}
複製代碼
在Kotlin中,filter函數被聲明爲內聯函數。這意味着filter函數,以及傳遞給它的lambda的字節碼會被一塊兒關聯到filter被調用的地方。最終,第一種實現所產生的字節碼和第二種實現所產生的字節碼大體同樣的。編譯器
於是Kotlin對內聯函數的支持讓你沒必要擔憂性能問題。
注意: 一、有大量元素須要處理,中間集合的運行開銷將成爲不可忽視的問題,於是使用asSequence調用,用序列來替代集合。 二、只在處理大量數據的集合時序列有用,小集合能夠用普通的集合操做處理便可。
使用inline
關鍵字只能提升帶有lambda
參數的函數的性能,其餘狀況須要額外的度量和研究。
對於普通的函數調用,JVM
已經提升了強大的內聯支持。它會分析代碼的執行,並在任何經過內聯可以帶來好處的時候將函數調用內聯。
帶lambda
參數的函數內聯能帶來的好處: