benf.org :  other :  cfr :  Java 8 Lambda Serialisation

I discussed java 8 lambdas in general here - but it's also really interesting to look at what happens in the case of serialisable lambdas....

Original code

@FunctionalInterface
public interface LambdaTest21<INPUT> extends Consumer<INPUT>, Serializable {
    public void acceptWithThrowing(INPUT input);

    @Override
    public default void accept(INPUT input) {
    }

    public default LambdaTest21<INPUT> andThen(LambdaTest21<INPUT> consumer) {
        return input -> {
            acceptWithThrowing(input);
        };
    }

    public default LambdaTest21<INPUT> butThen(LambdaTest21<INPUT> consumer) {
        return input -> {
            consumer.acceptWithThrowing(input);
        };
    }
}

CFR 0_35 decompilation

Other than a few unnecessary casts, a pretty good job...

@FunctionalInterface
public interface LambdaTest21<INPUT>
extends Consumer<INPUT>,
Serializable {
    public void acceptWithThrowing(INPUT var1);

    default public void accept(INPUT this_) {
    }

    default public LambdaTest21<INPUT> andThen(LambdaTest21<INPUT> lambdaTest21) {
        return arg_0 -> {
            this.acceptWithThrowing((INPUT)(arg_0));
        }
        ;
    }

    default public LambdaTest21<INPUT> butThen(LambdaTest21<INPUT> lambdaTest21) {
        return arg_0 -> {
            lambdaTest21.acceptWithThrowing((INPUT)(arg_0));
        }
        ;
    }
}

But - what about if we show it with less sugaring?

It gets quite interesting if you turn off some of CFR's resugaring options. - if we run CFR with --removeboilerplate false --decodelambdas false, we get a really interesting look at what actually ended up in the output.... be prepared to scroll!

@FunctionalInterface
public interface LambdaTest21<INPUT>
extends Consumer<INPUT>,
Serializable {
    public void acceptWithThrowing(INPUT var1);

    default public void accept(INPUT this_) {
    }

    default public LambdaTest21<INPUT> andThen(LambdaTest21<INPUT> lambdaTest21) {
        return (LambdaTest21<Object>)LambdaMetafactory.altMetaFactory(null, null, null, acceptWithThrowing(INPUT ), lambda$andThen$568f6e21$0(Object ), (Ljava/lang/Object;)V)((LambdaTest21)(this));
    }

    default public LambdaTest21<INPUT> butThen(LambdaTest21<INPUT> lambdaTest21) {
        return (LambdaTest21<Object>)LambdaMetafactory.altMetaFactory(null, null, null, acceptWithThrowing(INPUT ), lambda$butThen$568f6e21$0(LambdaTest21 Object ), (Ljava/lang/Object;)V)((LambdaTest21)(this), lambdaTest21);
    }

    default private static /* synthetic */ Object $deserializeLambda$(SerializedLambda serializedLambda) {
        switch (serializedLambda.getImplMethodName()) {
            case "lambda$andThen$568f6e21$0": {
                if ((((((serializedLambda.getImplMethodKind() != 9) || (!(serializedLambda.getFunctionalInterfaceClass().equals("org/benf/cfr/tests/LambdaTest21")))) || (!(serializedLambda.getFunctionalInterfaceMethodName().equals("acceptWithThrowing")))) || (!(serializedLambda.getFunctionalInterfaceMethodSignature().equals("(Ljava/lang/Object;)V")))) || (!(serializedLambda.getImplClass().equals("org/benf/cfr/tests/LambdaTest21")))) || (!(serializedLambda.getImplMethodSignature().equals("(Ljava/lang/Object;)V")))) break;
                return (LambdaTest21<Object>)LambdaMetafactory.altMetaFactory(null, null, null, acceptWithThrowing(INPUT ), lambda$andThen$568f6e21$0(Object ), (Ljava/lang/Object;)V)((LambdaTest21)((LambdaTest21)(serializedLambda.getCapturedArg(0))));
            }
            case "lambda$butThen$568f6e21$0": {
                if ((((((serializedLambda.getImplMethodKind() != 9) || (!(serializedLambda.getFunctionalInterfaceClass().equals("org/benf/cfr/tests/LambdaTest21")))) || (!(serializedLambda.getFunctionalInterfaceMethodName().equals("acceptWithThrowing")))) || (!(serializedLambda.getFunctionalInterfaceMethodSignature().equals("(Ljava/lang/Object;)V")))) || (!(serializedLambda.getImplClass().equals("org/benf/cfr/tests/LambdaTest21")))) || (!(serializedLambda.getImplMethodSignature().equals("(Lorg/benf/cfr/tests/LambdaTest21;Ljava/lang/Object;)V")))) break;
                return (LambdaTest21<Object>)LambdaMetafactory.altMetaFactory(null, null, null, acceptWithThrowing(INPUT ), lambda$butThen$568f6e21$0(LambdaTest21 Object ), (Ljava/lang/Object;)V)((LambdaTest21)((LambdaTest21)(serializedLambda.getCapturedArg(0))), (LambdaTest21)((LambdaTest21)(serializedLambda.getCapturedArg(1))));
            }
        }
        throw new IllegalArgumentException("Invalid lambda deserialization");
    }

    default public /* synthetic */ void lambda$butThen$568f6e21$0(LambdaTest21 lambdaTest21, Object object) {
        lambdaTest21.acceptWithThrowing((INPUT)(object));
    }

    default public /* synthetic */ void lambda$andThen$568f6e21$0(Object object) {
        this.acceptWithThrowing((INPUT)(object));
    }
}

Wow! - and that's also using a string switch, which is itself sugared


Last updated 09/2013