Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determine if a lambda expression is stateless or stateful in Java

Tags:

Is there a function which accepts a reference to a lambda expression and returns a boolean saying whether the lambda expression is stateless or not? How can the statefulness of a lambda expression be determined?

like image 566
snr Avatar asked Feb 20 '18 14:02

snr


People also ask

Is lambda stateful or stateless?

While AWS Lambda's programming model is stateless, your code can access stateful data by calling other web services, such as Amazon S3 or Amazon DynamoDB.

What is stateful lambda expression?

A stateful lambda expression is one whose result depends on any state that might change during the execution of a pipeline. On the other hand, a stateless lambda expression is one whose result does not depend on any state that might change during the execution of a pipeline.

What is stateless lambda?

The above execution model makes Lambda functions effectively stateless. This means that every time your Lambda function is triggered by an event it is invoked in a completely new environment. You don't have access to the execution context of the previous event.

What is stateless and stateful stream Java?

A stateful operation is the one whose result depends on any state that might change during the execution of the pipeline. Stateless operations retain no state during the execution of the pipeline.


2 Answers

Well, a lambda expression is just an instance of a special anonymous class that only has one method. Anonymous classes can "capture" variables that are in the surrounding scope. If your definition of a stateful class is one that carries mutable stuff in its fields (otherwise it's pretty much just a constant), then you're in luck, because that's how capture seems to be implemented. Here is a little experiment :

import java.lang.reflect.Field;
import java.util.function.Function;

public class Test {
    public static void main(String[] args) {
        final StringBuilder captured = new StringBuilder("foo");
        final String inlined = "bar";
        Function<String, String> lambda = x -> {
            captured.append(x);
            captured.append(inlined);

            return captured.toString();
        };

        for (Field field : lambda.getClass().getDeclaredFields())
            System.out.println(field);
    }
}

The output looks something like this :

private final java.lang.StringBuilder Test$$Lambda$1/424058530.arg$1

The StringBuilder reference got turned into a field of the anonymous lambda class (and the final String inlined constant was inlined for efficiency, but that's beside the point). So this function should do in most cases :

public static boolean hasState(Function<?,?> lambda) {
    return lambda.getClass().getDeclaredFields().length > 0;
}

EDIT : as pointed out by @Federico this is implementation-specific behavior and might not work on some exotic environments or future versions of the Oracle / OpenJDK JVM.

like image 94
ttzn Avatar answered Oct 04 '22 05:10

ttzn


No, it is not generally possible. The suggested approach of checking whether the lambda belongs to a class with a field is the next best thing, but having a field does not equal having a state.

class Stateless {
    int result = 0;
    public int getResult() { return result; }
}

It is possible to prove statefulness by finding two input sequence for which a given input combination returns a different result. However, it is not possible to prove that such a input sequence does not exist (any input sequence might produce a different result if prepended by another invocation).

(Even if you check the values of fields found via reflection, those might change without influencing the lambda's result, therefore not really making it stateful).

Here's a short compilable example showing both false positive and negatives, disproving the notion:

public class StatefulLambda {
    static AtomicInteger counter = new AtomicInteger();

    public static void main(String[] args) {
        // false negative: will return different result each call
        System.out.println(hasState(i -> counter.incrementAndGet()));

        // false positive: will always return the same result
        Object object = new Object() {
            final int i = 0;
        };
        System.out.println(hasState(i -> object.toString()));
    }

    private static boolean hasState(Function<?,?> lambda) {
        return lambda.getClass().getDeclaredFields().length > 0;
    }
}
like image 24
daniu Avatar answered Oct 04 '22 03:10

daniu