EDIT 1: I am aware this question has been marked as a duplicate and I initially deleted it. However, after reading in this Meta Post that deleting is bad and that I should edit my question rather than deleting it, I undeleted and am trying to improve the question for anyone else who might have the same issue I did.
After the post marked as "already answered" linked to something I already knew (and a post I've read often) but didn't represent my question/confusion, I tried to expand my test case and realized my problem was not in knowing about references, but rather misunderstanding of how autoboxing worked and the relationship between an Integer
reference and its (immutable) value. See edit below the original question which demonstrates what my confusion was.
Original Question:
I'm still trying to learn how to leverage Java 8+ lambda functional interfaces. While I know it's not necessarily a best practice to modify a parameter passed to a method, I am not sure why the input value to a lambda expression, modified within the expression, is not modified.
Here's an example program which I would expect to modify the value of its input (t
) to the value 42
:
import java.util.function.Consumer;
public class Main {
static Consumer<Integer> foo = n -> {
n = 42;
};
public static void main(String... args) {
Integer t = 0;
foo.accept(t);
System.out.println("Why is " + t + " not equal to 42?");
}
}
Output:
Why is 0 not equal to 42?
EDIT 2:
As has been pointed out by the first commenter, the problem was trying to reassign the parameter (an immutable Integer
container). I wasn't really trying to change the reference of the Integer
, I was trying to change the boxed value and assumed that Java would do that for me automagically. I was wrong.
Below, I have modified the earlier code to demonstrate what I thought would happen and what I was expecting. While the marked duplicate about "pass by value" is related and one of several associated issues, it was not the source of my confusion. It was ultimately my misunderstanding of how autoboxing works (creating a new object, rather than modifying the boxed value of the existing object) that was the root of my issue.
import java.util.function.Consumer;
public class Main {
/**
* How I thought {@link Integer} worked, not how it works.
*/
class BoxedInt {
int boxed;
BoxedInt(int i) {
box(i);
}
void box(int i) {
this.boxed = i;
}
int unbox() {
return boxed;
}
public String toString() {
return String.valueOf(unbox());
}
}
static Consumer<BoxedInt> foo = n -> {
n.box(42); // what I thought happened with n = 42
};
public static void main(String... args) {
BoxedInt t = new Main().new BoxedInt(0);
foo.accept(t);
System.out.println("See how " + t + " is equal to 42.");
}
}
Result:
See how 42 is equal to 42.