Table of Contents
Introduction
When we invoke a Java method and provide a primitive value (like an int, long, boolean, double, etc.) as an input parameter, Java creates a copy of that parameter and provides the method the new copy.
Inside of the method, we can update the value of that parameter and not have any impact on the calling code’s copy of that primitive variable.
Example
To show this in action, let’s look at some example code:
/**
* Because final is not present on the input parameter, this method's
* logic is free to assign a new value to copyOfPrimitiveValue.
* However, as this is a Java primitive value, a copy of the value is passed
* into the method, so none of the changes to the variable inside of the
* method will impact the calling code.
* @param copyOfPrimitiveValue A primitive variable, for which Java will
* create a copy when invoking the method.
* @return An incremented value of copyOfPrimitive.
*/
public static int demonstrateModifications(int copyOfPrimitiveValue) {
copyOfPrimitiveValue = copyOfPrimitiveValue + 1;
return copyOfPrimitiveValue;
}
@Nested
class DemonstrateModificationsTest {
@ParameterizedTest
@ValueSource(ints = {2, 3, -1, 10})
void demonstratModifications_whenInvoked_doesNotChangeInputVariablesForCallingCode(int value){
// Setup
System.out.format("Expect: %s%n", value);
// Execution
int result = PassByValueDemo.demonstrateModifications(value);
// Validation
assertEquals(value + 1, result);
System.out.format("Value: %s%n", value);
}
}
If we were to run the unit test, the output would also show us that no change is occurring, such as:
Expect: 2
Value: 2
Even though the demonstrateModifications method changed the value assigned to copyOfPrimitiveValue within the method, since it was a separate copy of that value in memory, it had no effect on the calling code. This is called pass by value. Both calling code and the methods it invokes have their own separate variable copies for primitive inputs.
The Final Keyword
The final keyword on an input parameter tells the compiler to enforce that we do not assign that input parameter a new value within that method. This can help with things like:
- copy/paste errors, or
- if we have a setter method that has a parameter with the same name as an instance field it is setting and we forget to include the this. prefix while trying to set the field’s value.
However, as a primitive value passed into a method is a copy of the original, the final keyword is not tied to whether or not we can change the value used in the calling code after our method completes.
/**
* If I tried to assign a new value to copyOfPrimitiveValue,
* within the method, then the code will not compile because of
* the final keyword. Uncomment the line in the method
* if you want an example.
*
* @param copyOfPrimitiveValue A primitive variable, for which Java will
* create a copy when invoking the method.
*/
public static int demonstrateFinal(final int copyOfPrimitiveValue) {
// copyOfPrimitiveValue = 3;
return copyOfPrimitiveValue;
}
@Nested
class DemonstrateFinalTest {
@ParameterizedTest
@ValueSource(ints = {2, 3, -1, 10})
void demonstrateFinal_whenInvoked_isNotAllowedToChangeFinalInputs(int value){
// Setup
// This isn't really necessary, but saving the value off in another variable
// for demonstration purposes.
int expectedValue = value;
System.out.format("Expect: %s%n", expectedValue);
// Execution
int result = PassByValueDemo.demonstrateFinal(value);
// Validation
assertEquals(value, result);
assertEquals(expectedValue, result);
System.out.format("Value: %s%n", value);
}
}
The test isn’t really necessary in this case, as the code with the final keyword will not compile if we un-comment the line that attempts to assign it a new value.
Summary
When invoking a method with a primitive, such as an int, boolean, long, etc., we need not worry about whether that method might modify the variable value. Java creates a copy of that variable and stores it separately in memory for the method to use. While the final keyword for input parameters does help catch issues in our code, but it is not tied to the method’s inability to modify primitive input parameters.

Leave a comment