高阶函数在编译后其实是用的匿名内部类的方式来实现,所以会有一点性能上的开销。使用 Inline 关键字来避免这种情形。被 Inline 关键字标记的高阶函数,在编译后是直接将高阶函数的函数体以及 Lambda 参数直接拷贝到调用处。这样就不会多创建匿名内部类或者方法引用实例,减少性能上的开销。
Define And Use
原则上任何函数都已加上inline
,但是最好是加载高阶函数中。
1
| Warning:(123, 4) Kotlin: Expected performance impact of inlining '...' can be insignificant. Inlining works best for functions with lambda parameters
|
lambda
不加inline 时:
1 2 3 4 5 6 7 8 9
| fun notInlinedFilter(list: List<Int>, predicate: (Int) -> Boolean): List<Int> { return list.filter(predicate) }
fun notInlinedTest() { val list = listOf(1, 2, 3) val newList = notInlinedFilter(list) { it < 2 } println(newList) }
|
编译后predicate
参数编译成一个Function1
接口的实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| @NotNull public static final List notInlinedFilter(@NotNull List list, @NotNull Function1 predicate) { Intrinsics.checkParameterIsNotNull(list, "list"); Intrinsics.checkParameterIsNotNull(predicate, "predicate"); Iterable $receiver$iv = (Iterable)list; Collection destination$iv$iv = (Collection)(new ArrayList()); Iterator var5 = $receiver$iv.iterator();
while(var5.hasNext()) { Object element$iv$iv = var5.next(); if ((Boolean)predicate.invoke(element$iv$iv)) { destination$iv$iv.add(element$iv$iv); } }
return (List)destination$iv$iv; }
public static final void notInlinedTest() { List list = CollectionsKt.listOf(new Integer[]{1, 2, 3}); List newList = notInlinedFilter(list, (Function1)new Function1<Integer, Boolean>() { @Override public Boolean invoke(Integer integer) { return integer < 2; } }); System.out.println(newList); }
|
使用inline
定义
1 2 3 4 5 6 7 8 9
| inline fun inlinedFilter(list : List<Int>, predicate : (Int) -> Boolean) : List<Int>{ return list.filter(predicate) }
fun lambdaInCallSiteTest() { val list = listOf(1,2,3) val newList = inlinedFilter(list) {it < 2} println(newList) }
|
查看编译后的代码。
- 申明处的函数
inlinedFilter
还是存在。所以Java 中的代码可以直接调用 Kotlin 中的 Inline 函数
- 在调用处,inline 函数直接用它的函数替换了
- 在调用处,lmabda参数
predicate
也被直接拷贝(翻译)过去了。在调用处直接被替代了。
- 调用处的的函数会被增大,行数变多。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public static final void lambdaInCallSiteTest() { List list = CollectionsKt.listOf(new Integer[]{1, 2, 3}); Iterable $receiver$iv$iv = (Iterable)list; Collection destination$iv$iv$iv = (Collection)(new ArrayList()); Iterator var5 = $receiver$iv$iv.iterator();
while(var5.hasNext()) { Object element$iv$iv$iv = var5.next(); int it = ((Number)element$iv$iv$iv).intValue(); if (it < 2) { destination$iv$iv$iv.add(element$iv$iv$iv); } }
List newList = (List)destination$iv$iv$iv; System.out.println(newList); }
@NotNull public static final List inlinedFilter(@NotNull List list, @NotNull Function1 predicate) { Intrinsics.checkParameterIsNotNull(list, "list"); Intrinsics.checkParameterIsNotNull(predicate, "predicate"); Iterable $receiver$iv = (Iterable)list; Collection destination$iv$iv = (Collection)(new ArrayList()); Iterator var6 = $receiver$iv.iterator();
while(var6.hasNext()) { Object element$iv$iv = var6.next(); if ((Boolean)predicate.invoke(element$iv$iv)) { destination$iv$iv.add(element$iv$iv); } }
return (List)destination$iv$iv; }
|
function refrence
1 2 3 4 5 6 7 8 9 10 11
| inline fun inlinedFilter(list : List<Int>, predicate : (Int) -> Boolean) : List<Int>{ return list.filter(predicate) }
fun filterLessThanTwo(input: Int) = input < 2
fun functionReferenceTest() { val list = listOf(1,2,3) val newList = inlinedFilter(list, ::filterLessThanTwo) println(newList) }
|
编译后的代码
- 申明处的函数
inlinedFilter
还是存在。所以Java 中的代码可以直接调用 Kotlin 中的 Inline 函数
- 在调用处,inline 函数直接用它的函数替换了
- 在调用处,inline 函数的参数(方法引用),直接编译到函数具体的调用处
- 调用处的函数行数会增多
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public static final boolean filterLessThanTwo(int input) { return input < 2; }
public static final void functionReferenceTest() { List list = CollectionsKt.listOf(new Integer[]{1, 2, 3}); Iterable $receiver$iv$iv = (Iterable)list; Collection destination$iv$iv$iv = (Collection)(new ArrayList()); Iterator var5 = $receiver$iv$iv.iterator();
while(var5.hasNext()) { Object element$iv$iv$iv = var5.next(); int p1 = ((Number)element$iv$iv$iv).intValue(); if (filterLessThanTwo(p1)) { destination$iv$iv$iv.add(element$iv$iv$iv); } }
List newList = (List)destination$iv$iv$iv; System.out.println(newList); }
@NotNull public static final List inlinedFilter(@NotNull List list, @NotNull Function1 predicate) { Intrinsics.checkParameterIsNotNull(list, "list"); Intrinsics.checkParameterIsNotNull(predicate, "predicate"); Iterable $receiver$iv = (Iterable)list; Collection destination$iv$iv = (Collection)(new ArrayList()); Iterator var6 = $receiver$iv.iterator();
while(var6.hasNext()) { Object element$iv$iv = var6.next(); if ((Boolean)predicate.invoke(element$iv$iv)) { destination$iv$iv.add(element$iv$iv); } } }
|
inline to inline
inline 函数的函数式类型参数是在调用处被转换,如果传入参数时已经是函数式类型的,则是转换不了的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| inline fun inlinedFilter(list : List<Int>, predicate : (Int) -> Boolean) : List<Int>{ return list.filter(predicate) }
fun filterLessThanTwo(input: Int) = input < 2
fun lambdaInstance(predicate: (Int) -> Boolean) { val list = listOf(1,2,3) val newList = inlinedFilter(list, predicate) println(newList) }
fun lambdaInstanceTest() { lambdaInstance(::filterLessThanTwo) }
|
编译后的代码,在lambdaInstance()
函数处的参数,还是是Function1
类型的实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| public static final boolean filterLessThanTwo(int input) { return input < 2; }
public static final void lambdaInstanceTest() { lambdaInstance((Function1) new Function1<Integer, Boolean>() { @Override public Boolean invoke(Integer integer) { return filterLessThanTwo(integer); } }); }
public static final void lambdaInstance(@NotNull Function1 predicate) { Intrinsics.checkParameterIsNotNull(predicate, "predicate"); List list = CollectionsKt.listOf(new Integer[]{1, 2, 3}); Iterable $receiver$iv$iv = (Iterable) list; Collection destination$iv$iv$iv = (Collection) (new ArrayList()); Iterator var6 = $receiver$iv$iv.iterator();
while (var6.hasNext()) { Object element$iv$iv$iv = var6.next(); if ((Boolean) predicate.invoke(element$iv$iv$iv)) { destination$iv$iv$iv.add(element$iv$iv$iv); } }
List newList = (List) destination$iv$iv$iv; System.out.println(newList); }
@NotNull public static final List inlinedFilter(@NotNull List list, @NotNull Function1 predicate) { Intrinsics.checkParameterIsNotNull(list, "list"); Intrinsics.checkParameterIsNotNull(predicate, "predicate"); Iterable $receiver$iv = (Iterable) list; Collection destination$iv$iv = (Collection) (new ArrayList()); Iterator var6 = $receiver$iv.iterator();
while (var6.hasNext()) { Object element$iv$iv = var6.next(); if ((Boolean) predicate.invoke(element$iv$iv)) { destination$iv$iv.add(element$iv$iv); } }
return (List) destination$iv$iv; }
|
可以将lambdaInstance()
定义为inline
函数,这样在调用lambdaInstance()
时的参数,就不会被编译成Function1
的实例的。
inline
函数的参数可以作为参数传递给另一个inline
函数
inline
函数参数不能被存储起来。因为编译后参数实际上是一段代码块,在真实的 Java 中是不能存储代码块到变量中的。
oninline
inline
函数的函数式类型的参数是不能被存储在变量中的,使用noinline
关键字标记这个函数式类型的参数后就可以被存储起来的。当然在调用处inline
函数的函数体还是会直接替换,只不过参数不会直接替换了
在inliene
的函数体内,如果也有 lambda 函数,在内嵌的 lambda 中是不能直接调用 inline 的函数式参数的。使用这个关键字规避
参考
Idiomatic Kotlin: Inline functions
functional_kotlin