I ran your test 10 times in a loop, and watched until the numbers stopped changing, so I could be sure that the result is valid. It is.
It’s because your stream is a LongStream, and LongStream.map takes a LongUnaryOperator
argument.
Looking at the generated bytecode, we can see that when you use a lambda, the compiler compiles it into a static singleton LongUnaryOperator
directly, but when you use a method reference, it gets a kotlin.jvm.functions.Function1
for the reference, and has to make a LongUnaryOperator
wrapper for it.
That Function1
is a generic interface that takes and returns objects, and that means that the wrapper has to box and unbox Long
to/from long
, and that is why it takes so much longer.
I don’t know why the kotlin compiler does this – the way it compiles method references certainly seems suboptimal. If you’re not using primitive types, though, the speed difference will go away.
Here’s relevant byte code that makes the wrapper.
public final invoke()V
L0
LINENUMBER 27 L0
ALOAD 0
GETFIELD LambdaspeedKt$main$$inlined$repeat$lambda$2.$array$inlined : [J
INVOKESTATIC java/util/Arrays.stream ([J)Ljava/util/stream/LongStream;
GETSTATIC LambdaspeedKt$main$2$2$1.INSTANCE : LLambdaspeedKt$main$2$2$1;
CHECKCAST kotlin/jvm/functions/Function1
DUP
IFNULL L1
ASTORE 1
NEW LambdaspeedKt$sam$i$java_util_function_LongUnaryOperator$0
DUP
ALOAD 1
INVOKESPECIAL LambdaspeedKt$sam$i$java_util_function_LongUnaryOperator$0.<init> (Lkotlin/jvm/functions/Function1;)V
L1