Using lambda and method reference differ significantly in performance with Java 8 streams

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
6 Likes