5

In one of the arguments about differences between lambdas and anonymous classes, in this post:

Java8 Lambdas vs Anonymous classes

I read a claim that "Lambdas can have state" just like anonymous class instances.

As far as I know, you cannot add user defined state that belongs exclusively to the lambda , since there is no way to define instance members on an implementation of a java lambda function.

For example:

Runnable r=  () -> { int x = 5;  }; // defines a local - no way to define instance
Runnable r2 = new Runnable() {
    int x;  // defines state via instance member
    @Override
    public void run() {
        // TODO Auto-generated method stub

    }
};

Just to clarify, I am not trying to introduce state to a lambda, as I think that goes against the intent. I am just trying to verify or disprove a claim of a technical nature that was made by a reputable source on the above stack overflow question.

Gonen I
  • 5,576
  • 1
  • 29
  • 60
  • What is "a lambda" for you? You can have `x -> { ... }` with lots of code inside the curly braces. – C-Otto Jan 23 '18 at 12:01
  • Where did you read this? – khelwood Jan 23 '18 at 12:05
  • @khelwood It was a comment by a user with 35K reputation on the above mentioned question – Gonen I Jan 23 '18 at 12:11
  • 1
    you may want to read: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#accessing-local-variables – Edwin Jan 23 '18 at 12:14
  • 1
    @user889742 See the further clarifying comments by the same user. Lambdas can access external variables, which means they can update state. – khelwood Jan 23 '18 at 12:15
  • OK, I guess that's like saying static functions can have state since the objects they have references to may be mutable. – Gonen I Jan 23 '18 at 12:18
  • @user889742 If you like, but even a method is just a function with a reference to an object (that might be mutable). – khelwood Jan 23 '18 at 12:23
  • 1
    I think they are discussing (in comments of the accepted answer) about an array that's in a lambda function and how they save a state in that array, is this what you've meant? but in the end is that not just modifying a variable? – Edwin Jan 23 '18 at 12:26
  • @Edwin OK, I see the hack they were talking about. Not natural object state. If anyone cares to put it in an answer, I'll probably accept that. – Gonen I Jan 23 '18 at 12:30
  • but as the guy says, that's gonna be a problem if you have mutliple threads, so I think it's not a "right" answer to give – Edwin Jan 23 '18 at 12:32
  • @Edwin that array is only one example, in principle, a lambda expression can capture a reference to an arbitrary mutable object, including a thread safe one. Also, this may even happen implicitly in a non-`static` context by simply accessing a field of the surrounding context, capturing the `this` reference. And, well, there is no requirement for every lambda expression to be thread safe. – Holger Jan 23 '18 at 18:09
  • You can also reach arbitrary mutable objects from static functions. You can even create a map object and store it in a static member on a pure Java interface to create "instance members". You can implement polymorphism in C by creating your own VTABLE from function pointers. These are all terrible ideas. – Gonen I Jan 23 '18 at 20:29

3 Answers3

11

Although the lambda function does not have anything like instance variables, it can update some state. Depending on how you regard this, you could say that the lambda function has its own state.

E.g.

Supplier<Integer> makeCountingLambda() {
    final int[] counter = new int[1];
    return (() -> ++counter[0]);
}

Supplier<Integer> f = makeCountingLambda();
f.get(); // 1
f.get(); // 2

f is a lambda function. It will supply a new value each time get() is called, because its state is updated.

Something like this seems to be what the referenced comment was describing.

khelwood
  • 55,782
  • 14
  • 81
  • 108
  • While I consider this a hack, and not real or natural object state, I am excepting this answer, as it explains what the comment was referring to in the original question as mentioned above. – Gonen I Jan 23 '18 at 13:17
  • 1
    You are going as far as showing that even *mutable state* is possible, but generally, lambda expressions may capture state from their surrounding context, which is neither, a bad thing nor counteracting intent. E.g, the predicate returned by `Predicate.isEqual("foo")` has been implemented by a lambda expression which captured the object reference I’ve passed to the method. Note that since `makeCountingLambda()` is not a `static` method, you could have something like `return () -> someInstanceField++;` which is not as hacky as the array, but shouldn’t be used where pure functions are expected… – Holger Jan 23 '18 at 17:57
  • I see no inherent problem with having lambdas capture state from the surrounding context, as long as you are aware that it belongs to another object. – Gonen I Jan 23 '18 at 21:00
3

Not sure about what do you mean by state. If your question is "can lambda carry values, that can be remembered every time I invoke the same lambda" then the answer is no. You can make some trick to reach this kind of behaviour but they are not intended for this. If you want to have a "state" then it is better for you to use a class!

Let me know if it was not your meaning!

Tommaso Pasini
  • 1,521
  • 2
  • 12
  • 16
  • That is indeed what I mean by state. Same as object state. – Gonen I Jan 23 '18 at 12:09
  • @user889742 If you want to retain state, you have to declare the variable as `static` – Greggz Jan 23 '18 at 12:10
  • 1
    the only way to have a state in a lambda is to use variables declared outside the lambda (note that they have to be modifiable if you want to modify them, e.g. Integer is not going to work, you will have to use AtomicInteger, List are fine). I don't know what @Greggz mean by making a variable static. But you have to be very very very aware about what static does in Java and I don't think it is helpful in this case. If you declare what you want to do exactly we can help you in a more effective way! – Tommaso Pasini Jan 23 '18 at 12:18
2

Short answer? No Long answer? Lambdas are not meant to have states. The overall idea of lambdas is based on having one-time functions. Please read the lambda documentation for more details. http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/Lambda-QuickStart/index.html Hope this helps.

Levon Asatryan
  • 195
  • 1
  • 1
  • 9