Final Local Variables in Methods
A final local variable need not be initialized in its declaration—that is, it can be a blank final local variable—but it must be initialized in the code before it is accessed. However, the compiler does not complain as long as the local variable is not accessed—this is in contrast to final fields that must be explicitly assigned a value, whether they are accessed or not.
In Example 5.9, the main() method at (15) in the class Warehouse defines a final local reference workLight at (16). The state of the object denoted by the reference workLight is changed at (17), but an attempt to change the value of the final instance field color of this object at (18) does not succeed. The compiler also reports an error at (19), since the reference value of the final local variable work-Light cannot be changed. A blank final local reference alarmLight is declared at (20). The compiler reports an error when an attempt is made to use this reference at (21) before it is initialized. The non-final local reference carLight at (22) also cannot be accessed at (22) before it is initialized. However, note that the compiler does not complain as long as the local variables at (20) and (22) are not accessed.
final Light workLight = new Light(); // (16) Final local variable.
workLight.setWatts(100); // (17) OK. Changing object state.
// workLight.color = “pink”; // (18) Not OK. Final instance field.
// workLight = new Light(); // (19) Not OK. Changing final reference.
final Light alarmLight; // (20) Blank final local variable.
// alarmLight.setWatts(200); // (21) Not OK. Not initialized.
Light carLight; // (22) Non-final local variable.
// carLight.setWatts(10); // (23) Not OK. Not initialized.
Local variables in certain contexts are considered to be implicitly declared final: an exception parameter of a multi-catch clause (§7.6, p. 397) and a local variable that refers to a resource in a try-with-resources statement (§7.7, p. 407).
final Parameters
A formal parameter can be declared with the keyword final preceding the parameter declaration in the method header. A final parameter is a special case of a blank final local variable. It is initialized with the value of the corresponding argument in the method call, before the code in the body of the method is executed. Declaring parameters as final prevents their values from being changed inadvertently in the method. A formal parameter’s declaration as final does not affect the caller’s code.
In the declaration of the main() method at (15) in Example 5.9, the parameter args is declared as final. The array args will be initialized with the program arguments on the command line when execution starts.
public static void main(final String[] args) { // (15) Final parameter
// …
out.println(“Fun with final parameter args:”);
out.println(Arrays.toString(args)); // (24) Print array.
out.println(“args length: ” + args.length); // (25) Access final field
args[0] = “1”; // (26) OK. Modifying array state.
out.println(Arrays.toString(args)); // Print array.
//args = null; // (27) Not OK. Final parameter.
//args.length = 10; // (28) Not OK. Final instance field.
}
The state of the array object args is printed at (24). Its final field length is accessed at (25). The state of the args array is changed at (26), and is printed again. However, the compiler will not allow the reference value of the final parameter args to be changed at (27), nor will it allow the value of the final instance field args.length to be changed at (28).