람다의 패널티
람다는 컴파일 단계에서 파라미터 개수에 따라 FunctionN
형태의 함수 객체를 만들고 호출한다.
따라서 람다식을 사용하게 되면 일반적인 함수의 구현에 비해 추가적인 비용이 들기 때문에 오버헤드가 발생해서 덜 효율적이게 된다.
인라인 함수
람다식을 일반 함수처럼 효율적으로 만들어주는게 인라인 함수이고 inline
키워드를 붙이면 그 함수를 호출하는 지점이 inline
되어서 컴파일 단계에서 함수를 호출하는 코드 대신에 함수 본문의 코드 자체가 삽입된다.
함수 / 인라인 함수 - 코드 비교
fun main() {
var result = calc(2, 3) { a: Int, b: Int -> a + b }
println(result)
}
fun calc(a: Int, b: Int, op: (Int, Int) -> Int): Int {
println("called calc function")
return op(a, b)
}
// called calc function
// 5
fun main() {
var result = calc(2, 3) { a: Int, b: Int -> a + b }
println(result)
}
inline fun calc(a: Int, b: Int, op: (Int, Int) -> Int): Int {
println("called calc function")
return op(a, b)
}
// called calc function
// 5
함수 / 인라인 함수 - 바이트 코드 비교
public static final void main() {
int result = calc(2, 3, (Function2)null.INSTANCE);
boolean var1 = false;
System.out.println(result);
}
public static final int calc(int a, int b, @NotNull Function2 op) {
Intrinsics.checkNotNullParameter(op, "op");
String var3 = "called calc function";
boolean var4 = false;
System.out.println(var3);
return ((Number)op.invoke(a, b)).intValue();
}
public static final void main() {
byte a$iv = 2;
int b$iv = 3;
int $i$f$calc = false;
String var4 = "called calc function";
boolean var5 = false;
System.out.println(var4);
int var8 = false;
int result = a$iv + b$iv;
boolean var9 = false;
System.out.println(result);
}
public static final int calc(int a, int b, @NotNull Function2 op) {
int $i$f$calc = 0;
Intrinsics.checkNotNullParameter(op, "op");
String var4 = "called calc function";
boolean var5 = false;
System.out.println(var4);
return ((Number)op.invoke(a, b)).intValue();
}
main()
함수가 다르다는 것을 확인할 수 있다.- 인라인 함수가 아닌 경우는
Function2
함수 객체를 만들어서 호출한다. - 인라인 함수인 경우는
calc()
함수 본문 코드가 삽입되어서 호출한다. inline
을 사용하여 함수를 인라인 함수로 컴파일하게 되면 프로그램의 크기는 커지게 되지만 함수 호출의 오버헤드가 줄어서 처리가 빨라지기 떄문에 컬렉션의 요소를 반복할 때 등에 효율적이다.