-2

I have a functional interface in Java 8:

public interface IFuncLambda1 {
    public int someInt();
}

in main:

IFuncLambda1 iFuncL1 =  () -> 5;
System.out.println("\niFuncL1.someInt: " + iFuncL1.someInt());
iFuncL1 = () -> 1;
System.out.println("iFuncL1.someInt: " + iFuncL1.someInt());

Running this will yield:

iFuncL1.someInt: 5
iFuncL1.someInt: 1

Is this functionality OK as it is? Is it intended?

If the overriding would be done in an implementing class, and the implementation would change at some point, then in every place that that method is called, the behaviour would be the same, we would have consistency. But if I change the behaviour/implementation through lambda expressions like in the example, the behaviour will only be valid til the next change, later on in the flow. This feels unreliable and hard to follow.

EDIT: @assylias I don't see how someInt() has its behaviour changed... What if I added a param to someInt and have this code:

IFuncLambda1 iFuncL1 =  (x) -> x - 1;
System.out.println("\niFuncL1.someInt: " + iFuncL1.someInt(var));
iFuncL1 = (x) -> x + 1;
System.out.println("iFuncL1.someInt: " + iFuncL1.someInt(var));

with var being a final even, how would you re-write that with classes?

Ade
  • 5
  • 1
  • 2
    There's no overriding here. What's happening is you are simply mutating a mutable local variable (that holds a reference to an object of type IFuncLambda). The underlying functions are not mutated, any more than doing "i = 3; i = 4" somehow "mutates" or "destroys" the number 3. – Brian Goetz Nov 05 '14 at 17:27
  • you're talking about a value/state and not a behaviour – Ade Nov 06 '14 at 09:10
  • Lambdas *are* values. – Brian Goetz Nov 06 '14 at 14:07
  • But I'm calling someInt(), and it has a different behaviour, this is what I said in other comments and this is the thing that I cannot get past; added another example in my post. – Ade Nov 06 '14 at 16:40

1 Answers1

4

In your example, () -> 5 is one object and () -> 1 is another object. You happen to use the same variable to refer to them but that is just how references work in Java.

By the way it behaves exactly the same way as if you had used anonymous classes:

IFuncLambda1 iFuncL1 =  new IFuncLambda1() { public int someInt() { return 5; } };
System.out.println("\niFuncL1.someInt: " + iFuncL1.someInt());
iFuncL1 =  new IFuncLambda1() { public int someInt() { return 1; } };
System.out.println("iFuncL1.someInt: " + iFuncL1.someInt());

Or using "normal" classes:

public static class A implements IFuncLambda1 {
    private final int i;
    public A(int i) { this.i = i; }
    public int someInt() { return i; }
}

IFuncLambda1 iFuncL1 =  new A(5);
System.out.println("\niFuncL1.someInt: " + iFuncL1.someInt());
iFuncL1 =  new A(1);
System.out.println("iFuncL1.someInt: " + iFuncL1.someInt());

There again there are two instances of A but you lose the reference to the first instance when you reassign iFuncL1.

assylias
  • 321,522
  • 82
  • 660
  • 783
  • 2
    And it would be the same behavior, if ordinary (i.e. non-anonymous) classes were used… – Holger Nov 05 '14 at 19:31
  • @Holger example, please, using 1 class and calling it twice, but changing behaviour between calls – Ade Nov 06 '14 at 09:14
  • I agree it's the same as anonymous class, and I would edit out the 'lambda' from title if I knew how. But you're basically telling me to treat the someInt() method as a variable instead of as a method. If I see it declared once up top somewhere and I wanna use it lower in the code, I have no guarantee that's the functionality Ima get (just imagine it processes a parameter I'm giving it), but instead I have to search all occurrences of it, just like checking if a variable has been changed since it was first initialized... – Ade Nov 06 '14 at 09:20
  • @Ade you seem to misunderstand what a variable represents in Java. `() -> 5` is a lambda object and is immutable - it never changes. `iFuncL1` is a variable. It's as if you said: I can write `String s = "abc"; s = "def";` so strings are mutable... You can edit your question (and its title) by clicking on the edit link below it. – assylias Nov 06 '14 at 09:21
  • thx, edited the question and my comment here; it posted before I got the chance to finish writing because Enter doesn't do newline heh – Ade Nov 06 '14 at 09:29
  • @Ade well yes `iFuncL1` is a variable that refers to a lambda, it's not a lambda itself. Like in `String s = "asf"` s is not a String, it's a variable that refers to a String. Now reusing the same variable with different values can be confusing but it's up to you not to do that... You may want to read [this](http://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value) - it explains how references work in Java. – assylias Nov 06 '14 at 09:43
  • "But you're basically telling me to treat the someInt() method as a variable instead of as a method. If I see it declared once up top somewhere and I wanna use it lower in the code, I have no guarantee that's the functionality Ima get (just imagine it processes a parameter I'm giving it), but instead I have to search all occurrences of it, just like checking if a variable has been changed since it was first initialized..." – Ade Nov 06 '14 at 10:10
  • 1
    @Ade I have added an example with a "normal" class - I hope it clarifies your issue. – assylias Nov 06 '14 at 12:03
  • @Ade: If you want to be sure that a variable doesn’t change, just declare it as `final`. That’s exactly what it is for. – Holger Nov 06 '14 at 13:29