Why should I use the keyword "final" on a method parameter in Java?
Solution 1
Stop a Variable’s Reassignment
While these answers are intellectually interesting, I've not read the short simple answer:
Use the keyword final when you want the compiler to prevent a variable from being re-assigned to a different object.
Whether the variable is a static variable, member variable, local variable, or argument/parameter variable, the effect is entirely the same.
Example
Let’s see the effect in action.
Consider this simple method, where the two variables (arg and x) can both be re-assigned different objects.
// Example use of this method:
// this.doSomething( "tiger" );
void doSomething( String arg ) {
String x = arg; // Both variables now point to the same String object.
x = "elephant"; // This variable now points to a different String object.
arg = "giraffe"; // Ditto. Now neither variable points to the original passed String.
}
Mark the local variable as final. This results in a compiler error.
void doSomething( String arg ) {
final String x = arg; // Mark variable as 'final'.
x = "elephant"; // Compiler error: The final local variable x cannot be assigned.
arg = "giraffe";
}
Instead, let’s mark the parameter variable as final. This too results in a compiler error.
void doSomething( final String arg ) { // Mark argument as 'final'.
String x = arg;
x = "elephant";
arg = "giraffe"; // Compiler error: The passed argument variable arg cannot be re-assigned to another object.
}
Moral of the story:
If you want to ensure a variable always points to the same object, mark the variable final.
Never Reassign Arguments
As good programming practice (in any language), you should never re-assign a parameter/argument variable to an object other than the object passed by the calling method. In the examples above, one should never write the line arg =
. Since humans make mistakes, and programmers are human, let’s ask the compiler to assist us. Mark every parameter/argument variable as 'final' so that the compiler may find and flag any such re-assignments.
In Retrospect
As noted in other answers… Given Java's original design goal of helping programmers to avoid dumb mistakes such as reading past the end of an array, Java should have been designed to automatically enforce all parameter/argument variables as 'final'. In other words, Arguments should not be variables. But hindsight is 20/20 vision, and the Java designers had their hands full at the time.
So, always add final
to all arguments?
Should we add final
to each and every method parameter being declared?
- In theory, yes.
- In practice, no.
➥ Addfinal
only when the method’s code is long or complicated, where the argument may be mistaken for a local or member variable and possibly re-assigned.
If you buy into the practice of never re-assigning an argument, you will be inclined to add a final
to each. But this is tedious and makes the declaration a bit harder to read.
For short simple code where the argument is obviously an argument, and not a local variable nor a member variable, I do not bother adding the final
. If the code is quite obvious, with no chance of me nor any other programmer doing maintenance or refactoring accidentally mistaking the argument variable as something other than an argument, then don’t bother. In my own work, I add final
only in longer or more involved code where an argument might mistaken for a local or member variable.
#Another case added for the completeness
public class MyClass {
private int x;
//getters and setters
}
void doSomething( final MyClass arg ) { // Mark argument as 'final'.
arg = new MyClass(); // Compiler error: The passed argument variable arg cannot be re-assigned to another object.
arg.setX(20); // allowed
// We can re-assign properties of argument which is marked as final
}
record
Java 16 brings the new records feature. A record is a very brief way to define a class whose central purpose is to merely carry data, immutably and transparently.
You simply declare the class name along with the names and types of its member fields. The compiler implicitly provides the constructor, getters, equals
& hashCode
, and toString
.
The fields are read-only, with no setters. So a record
is one case where there is no need to mark the arguments final
. They are already effectively final. Indeed, the compiler forbids using final
when declaring the fields of a record.
public record Employee( String name , LocalDate whenHired ) // 🡄 Marking `final` here is *not* allowed.
{
}
If you provide an optional constructor, there you can mark final
.
public record Employee(String name , LocalDate whenHired) // 🡄 Marking `final` here is *not* allowed.
{
public Employee ( final String name , final LocalDate whenHired ) // 🡄 Marking `final` here *is* allowed.
{
this.name = name;
whenHired = LocalDate.MIN; // 🡄 Compiler error, because of `final`.
this.whenHired = whenHired;
}
}
Solution 2
Sometimes it's nice to be explicit (for readability) that the variable doesn't change. Here's a simple example where using final
can save some possible headaches:
public void setTest(String test) {
test = test;
}
If you forget the 'this' keyword on a setter, then the variable you want to set doesn't get set. However, if you used the final
keyword on the parameter, then the bug would be caught at compile time.
Solution 3
Yes, excluding anonymous classes, readability and intent declaration it's almost worthless. Are those three things worthless though?
Personally I tend not to use final
for local variables and parameters unless I'm using the variable in an anonymous inner class, but I can certainly see the point of those who want to make it clear that the parameter value itself won't change (even if the object it refers to changes its contents). For those who find that adds to readability, I think it's an entirely reasonable thing to do.
Your point would be more important if anyone were actually claiming that it did keep data constant in a way that it doesn't - but I can't remember seeing any such claims. Are you suggesting there's a significant body of developers suggesting that final
has more effect than it really does?
EDIT: I should really have summed all of this up with a Monty Python reference; the question seems somewhat similar to asking "What have the Romans ever done for us?"
Solution 4
Let me explain a bit about the one case where you have to use final, which Jon already mentioned:
If you create an anonymous inner class in your method and use a local variable (such as a method parameter) inside that class, then the compiler forces you to make the parameter final:
public Iterator<Integer> createIntegerIterator(final int from, final int to)
{
return new Iterator<Integer>(){
int index = from;
public Integer next()
{
return index++;
}
public boolean hasNext()
{
return index <= to;
}
// remove method omitted
};
}
Here the from
and to
parameters need to be final so they can be used inside the anonymous class.
The reason for that requirement is this: Local variables live on the stack, therefore they exist only while the method is executed. However, the anonymous class instance is returned from the method, so it may live for much longer. You can't preserve the stack, because it is needed for subsequent method calls.
So what Java does instead is to put copies of those local variables as hidden instance variables into the anonymous class (you can see them if you examine the byte code). But if they were not final, one might expect the anonymous class and the method seeing changes the other one makes to the variable. In order to maintain the illusion that there is only one variable rather than two copies, it has to be final.
Solution 5
I use final all the time on parameters.
Does it add that much? Not really.
Would I turn it off? No.
The reason: I found 3 bugs where people had written sloppy code and failed to set a member variable in accessors. All bugs proved difficult to find.
I'd like to see this made the default in a future version of Java. The pass by value/reference thing trips up an awful lot of junior programmers.
One more thing.. my methods tend to have a low number of parameters so the extra text on a method declaration isn't an issue.
Admin
Updated on February 16, 2021Comments
-
Admin over 3 years
I can't understand where the
final
keyword is really handy when it is used on method parameters.If we exclude the usage of anonymous classes, readability and intent declaration then it seems almost worthless to me.
Enforcing that some data remains constant is not as strong as it seems.
If the parameter is a primitive then it will have no effect since the parameter is passed to the method as a value and changing it will have no effect outside the scope.
If we are passing a parameter by reference, then the reference itself is a local variable and if the reference is changed from within the method, that would not have any effect from outside of the method scope.
Consider the simple test example below. This test passes although the method changed the value of the reference given to it, it has no effect.
public void testNullify() { Collection<Integer> c = new ArrayList<Integer>(); nullify(c); assertNotNull(c); final Collection<Integer> c1 = c; assertTrue(c1.equals(c)); change(c); assertTrue(c1.equals(c)); } private void change(Collection<Integer> c) { c = new ArrayList<Integer>(); } public void nullify(Collection<?> t) { t = null; }
-
hhafez over 15 yearsYou lost me from "But if they are not final...." Can you put try to rephrase it, Maybe I haven't had enough cofee.
-
Michael Borgwardt over 15 yearsYou have a local variables from - the question is what happens if you use the anon class instance inside the method and it changes the values of from - people would expect the change to be visible in the method, since they see only one variable. In order to avoid this confusion, it must be final.
-
James Schek over 15 yearsBut to paraphrase Krusty with his danish, what have they done for us LATELY? =)
-
vickirk over 14 yearsIt doesn't make a copy, it is simply a reference to whatever object was referenced.
-
Michael Borgwardt over 14 years@vickirk: sure it makes a copy - of the reference, in case of reference types.
-
Jeff Axelrod about 13 yearsI was about to suggest this as well, that final be the default in future versions and that you have to specify "mutable" or better keyword that is conceived. Here's a nice article about this: lpar.ath0.com/2008/08/26/java-annoyance-final-parameters
-
Pacerier over 12 yearsBtw assuming we do not have anonymous classes referencing those variables, are you aware if there's any difference between a
final
function parameter and a non-final function parameter in the eyes of HotSpot? -
Michael Borgwardt over 12 years@Pacerier: I'm pretty sure there is no difference to HotSpot
-
AvrDragon about 12 yearsbtw you will see warning "The assignment to variable test has no effect" anyway
-
gonzobrains almost 12 yearsYuval. That's funny! I guess peace can happen even if it is enforced by sword blade!
-
Sumit Desai about 11 years@AvrDragon But, we might ignore the warning as well. So, it's always better to have something which will stop us from going further, like a compilation error, which we will get by using the final keyword.
-
Sumit Desai about 11 years@MichaelBorgwardt I have a confusion. Creating a copy in case of primitives is fine. But, in case of objects, why can't it use the same reference instead of creating a copy, as ultimately only references are going to be stored in stack. But, the actual object is going to reside in heap.
-
Michael Borgwardt about 11 years@Sumit Desai: only the reference is copied - about the same time and space overhead as copying a primitive.
-
Sumit Desai about 11 years@MichaelBorgwardt Ok. Got it
-
arkon almost 11 years@AvrDragon That's dependent upon the development environment. You shouldn't be relying on the IDE to catch stuff like this for you anyways, unless you want to develop bad habits.
-
AvrDragon almost 11 years@b1naryatr0phy actually it's a compiler warning, not just IDE-tip
-
NobleUplift over 10 yearsThe question seems more similar to asking, "What haven't the Romans done for us?", because it's more of a critique on what the final keyword doesn't do.
-
Stijn de Witt over 10 years"As good programming practice (in any language), you should never re-assign a parameter/argument variable [..]" Sorry I really have to call you out on this one. Re-assigning arguments is standard practice in languages like Javascript, where the amount of arguments passed (or even if there are any passed) is not dictated by the method signature. E.g. given a signature like: "function say(msg)" people will make sure argument 'msg' is assigned, like so: "msg = msg || 'Hello World!';". The best Javascript programmers in the world are breaking your good practice. Just read the jQuery source.
-
Basil Bourque over 10 years@StijndeWitt Your example shows the very problem of reassigning the argument variable. You lose information with nothing gained in return: (a) You've lost the original value passed, (b) You've lost the intention of the calling method (Did caller pass 'Hello World!' or did we default). Both a & b are useful for testing, long code, and when the value is further changed later. I stand by my statement: arg vars should never be reassigned. Your code should be:
message = ( msg || 'Hello World"' )
. There is simply no reason not to use a separate var. The only cost is a few bytes of memory. -
Basil Bourque about 10 years@StijndeWitt An interesting article on this topic: lpar.ath0.com/2008/08/26/java-annoyance-final-parameters
-
Stijn de Witt about 10 years@Basil: It's more code (in bytes) and in Javascript that does count. Heavily. As with many things it's opinion based. It's entirely possible to completely ignore this programming practice and still write excellent code. One person's programming practice does not make it everyone's practice. Stand by it all you will, I choose to write it different anyway. Does that make me a bad programmer, or my code bad code?
-
Oscar almost 10 yearsSince it's a copy of the reference the variable won't get set anyway. Outside the test method, you will still have the original test reference
-
dev over 9 yearsit's also a good idea to implement an automated quality checker like findbugs to prevent common errors
-
Beni Cherniavsky-Paskin about 9 yearsUsing
message = ( msg || 'Hello World"' )
risks me later accidentally usingmsg
. When the contract I intend is "behavior with no/null/undefined arg is indistinguirhable from passing"Hello World"
", it's a good programming practice to commit to it early in the function. [This can be achieved without reassignment by starting withif (!msg) return myfunc("Hello World");
but that gets unwieldy with multiple arguments.] In the rare cases where the logic in the function should care whether the default was used, I'd rather designate a special sentinel value (preferrably public). -
Beni Cherniavsky-Paskin about 9 yearsExactly, it's not part of the function interface, only implementation. It's confusing that java allows (but dirsregards)
final
on parameters in interfaces / abstract method declarations. -
Stuart Rossiter over 8 years"Are you suggesting there's a significant body of developers suggesting that final has more effect than it really does?" For me that is the main problem: I strongly suspect a significant proportion of developers using it think that it enforces immutability of the caller's passed items when it doesn't. Of course, one then gets drawn into the debate on whether coding standards should 'protect against' conceptual misunderstandings (which a 'competent' developer should be aware of) or not (and this then heads towards an out-of-SO-scope opinions-type question)!
-
Stuart Rossiter over 8 years@Oscar "Since it's a copy of the reference the variable won't get set anyway. Outside the test method, you will still have the original test reference". I think you've misunderstood the answer. The "variable you want to set" is the class field (i.e.,
this.test
here); an understanding of how Java argument passing works is already implicit in the answer. -
Stuart Rossiter over 8 years@SumitDesai "But, we might ignore the warning as well. So, it's always better to have something which will stop us from going further, like a compilation error, which we will get by using the final keyword." I take your point but this is a very strong statement that I think many Java developers would disagree with. Compiler warnings are there for a reason and a competent developer shouldn't need an error to 'force' them to consider its implications.
-
Nir Alfasi about 8 years@BeniCherniavsky-Paskin the risk you describe is only because of the similarity between
message
andmsg
. But if he would call it something likeprocessedMsg
or something else that provides additional context - the chance of a mistake is much lower. Focus on what he says not on "how" he says it. ;) -
Darrell Teague almost 8 yearsIndeed, the problem with final is that it only enforces the reference is unchanged, gleefully allowing the referenced object members to be mutated, unbeknownst to the caller. Hence the best practice in this regard is defensive programming on the caller side, creating deeply immutable instances or deep copies of objects that are in danger of being mugged by unscrupulous APIs.
-
Darrell Teague over 7 yearsNot sure IDE and tool references are applicable to OP posting or the topic. Namely "final" is a compile-time check that the reference is not changed/mugged. Further, to really enforce such things see answer about no protection to child members of final references. When building an API for example, using an IDE or tool is not going to help external parties using/extending such code.
-
Wei Qiu almost 7 yearsThat's why java doen't have true closure.
-
Lawrence Dol almost 7 years"Never Reassing Arguments". Ummm, no, in programming never say "never", except to say "never say never". There are a number of legitimate use-cases for assigning to an argument; defaulting, preprocessing, decoding, to name a few. I wish programmers would stop saying "never"; they are almost always incorrect when they do.
-
Sarthak Mittal over 6 years@Jon Skeet: Suppose I have a method argument declared as final, and an inner class inside the method, but I don't use that final argument inside my inner class, will my final reference be eligible for garbage collection?
-
Jon Skeet over 6 years@SarthakMittal: The value won't be copied unless you actually use it, if that's what you're wondering.
-
Leo Lei over 6 years@LawrenceDol At a theoretical level, I hate saying "never" because there are always exceptions where a banned approach is really best for the situation. However, at a practical level, I really love it because it enforces rules and reduces the amount of decision making many programmers need to make when collaborating on the shared codebase, it makes the overall design consistent, with just the right amount (minimal amount) of exceptions. Thus, it might be more accurate to say: "Always prefer A and only do B if A cannot solve the problem".
-
Sarthak Mittal over 6 years@JonSkeet Yes, that was exactly I was wondering :), couldn't get around the idea that if the final variable can be used inside the inner class, then surely it cannot go out of scope once the method finishes! Michael Borgwardt's answer elaborated exactly that. Many thanks! :)
-
user949300 over 6 yearsWhy should I care that arg now points to "giraffe"? Nobody outside of my function sees the change! As you note in your final section, the only bug that might happen by you changing something you shouldnt is not prevented by final.. For a method parameter, final is a waste of time that only provides a false benefit.
-
user949300 over 6 yearsIt's been a long time, but could you provide an example of the bug you caught?
-
Craig van Wilson over 6 yearsSee the most voted for answer. That has a really good example where the member variable is not set and instead the parameter is mutated.
-
Madbreaks about 6 yearsDownvoting as misleading: Use the keyword final when you want the compiler to prevent a variable from being re-assigned to a different object." -- but it's only reassigned inside your method. The assignment has no affect from where the method was called; Java is strictly pass by value (where the value is a pointer). javadude.com/articles/passbyvalue.htm
-
Madbreaks about 6 years"the problem with final is that it only enforces the reference is unchanged" -- Untrue, Java itself prevents that. A variable passed into a method cannot have its reference changed by that method.
-
Basil Bourque about 6 years@Madbreaks You missed my main point. The scope is irrelevant, in all scopes inside and outside of a method, the effect of
final
on any variable is to stop the reassignment of another object to the reference. For argument/parameter I opined thatfinal
is indeed quite valuable in guaranteeing that the original intent of the calling programmer is maintained throughout the body of the receiving method, so we do not “forget” what was passed. While you may not value that benefit, that does not make the benefit “false”. I simply explained the effect of, and possible usefulness offinal
there. -
Darrell Teague about 6 yearsPlease research before posting... stackoverflow.com/questions/40480/…
-
Darrell Teague about 6 yearsSimply put, if it were true that references to references cannot be changed, there would be no discussion of defensive-copying, immutability, no need for final keyword, etc.
-
Madbreaks about 6 yearsEither you're misunderstanding me, or you're mistaken. If I pass an object reference to a method, and that method reassigns it, the original reference remains intact for (me) the caller when the method completes its execution. Java is strictly pass-by-value. And you're brazenly presumptuous to assert I've done no research.
-
Madbreaks about 6 yearsDownvoting because op asked why use final, and you gave just one, incorrect reason.
-
Darrell Teague about 6 yearsThe facts are there... some minor semantics about the reference being passed by value but the reference (pointer - I program in "C" too) ... can point to anything as the example provided shows. This results in the returned value being changed. As to the OP "question"... an earlier comment read "This is not a question, it's a statement of your opinion"... so there is some disagreement as to whether there was a question in there at all rather than a rather ambiguous discussion about the use of the final keyword.
-
t.y about 6 years@user949300 Nobody outside of your function sees the change... until they have to debug it. Adding
final
means there's one less thing you could've done (wrong). -
Kröw almost 6 yearsIf I have a method that takes in an int, increments it, and uses that same incremented value 12 different times, (then returns. This is all it does.), then I see no good reason not to directly increment the int parameter of the method. There is simply no point in creating a new variable to store this incremented value if you have absolutely no use for the original value; just write over the original value. As a matter of fact, having two different variables to keep track of (one useless parameter and another heavily referenced local variable) simply clogs up code. I'll stick to reassignment.
-
Basil Bourque almost 6 years@Kröw When tracing, troubleshooting, debugging, logging, and monitoring, I want to know my inputs. You can do what you want, but why throw away important information with nothing gained? Are you really programming for deployment to a computer/device so severely constrained that you cannot afford 32-bits for a second integer?
-
Darrell Teague almost 6 yearsBe cateful to differentiate an IDE from a runtime JVM. Whatever an IDE does is irrelevant when the compiled byte code runs on the server unless IDE added code to protect against member variable mugging such as a flaw in code when it was intended that a variable should not be reassigned but mistakenly was - hence the purpose of final keyword.
-
patrik over 3 years"As good programming practice (in any language), you should never re-assign a parameter/argument variable to an object other than the object passed by the calling method." I would have to call you out on this one. There is even a function for it in STL in c++. cplusplus.com/reference/algorithm/swap
-
Basil Bourque over 3 years@patrik I would not hold up C++ as a model of a wisely-designed language. But to each his own. And, as I said in my Answer, if recycling a few bits is critical to your app in an extremely memory-constrained environment, swapping out arguments might be justifiable. But that would be specialized hardware, not business-oriented apps on general-purpose computers.
-
matbrgz almost 3 yearsA record declaration is different from its constructor - the declaration has new, more precise syntax where it has been decided that final does not make sense. The constructor is not special - it has always been possible to declare a constructor parameter final.
-
mjs almost 3 years@BasilBourque I am confused why are arguing for final in method args when you state in your post that you only use it for specific cases. It has no use as I am in a project right now with finals everywhere. I can easily track the param and see where it is used and set by just putting my cursor on it. All light up. I don't need finals everywhere for some wierd case where the original author of the method decided you should not overwrite this param. If I now want to do just that, such as reassigning it, because say it was null, i can not. It makes no use in Java other than for very specific...
-
mjs almost 3 yearsIf I want to reassigning it, because say it was null, i can not. I have to introduce another one, and then if else to set the new one, and reassign the param to that and then use that. I just added complexity to the code BECAUSE of final.
-
Darrell Teague over 2 yearsThis is great discussion but one thing I think that is missed here is the practical bug side of at least being aware that in Java (and many other languages) ... passing a reference to some method (and Java copies it but ...) still has other references. So making for example a reference to a Map as final does not prevent any member thereof from being modified (say by some downstream method). The Map itself in that example is not immutable (its member references may be changed). Only its reference in the context of where final was used is.
-
Darrell Teague over 2 yearsGet into some meaty project, download and compile it... get hundreds of 'oh you can ignore those' warnings and... you have the Hindenberg in the making. Many of us adhere to a pretty strict 'no compile warnings allowed' way of working. There are some VERY rare exceptions but even these should be weeded out.
-
Basil Bourque over 2 years@mmm See my first Comment above. Reassigning a different value to an argument variable discards potentially vital information (the passed value) while gaining nothing in return beyond saving a few octets of memory. When programming on mobile devices, laptops, desktops, and servers that all have gigabytes of memory, such as trade-off is not justified. Just declare another local variable. I am baffled by the amount of consternation this simple issue raises amongst a few people.
-
Basil Bourque over 2 years@DarrellTeague Your point is valid, but applies to any collection variable anywhere. The context in this Answer here is the more narrow case of variables: arguments. In all but the simplest code, I would label all arguments as
final
, whether aCollection
or not. With all my arguments, I want to preserve the original passed value. Generally the calling method should practice defensive programming, and pass immutable data, or if not practical, at least pass data it no longer cares to maintain/access. That might mean passing a copy. -
Darrell Teague over 2 yearsExcellent point @BasilBourque. However, references go beyond collections and so, to further your point, good defensive programming is really what is the solution here. My default preference is designing with immutability, which Joshua Bloch espouses as well. The current programming model from Spring et al is confusing junior devs with bean-style (public) get/set default methods for every attribute. No wonder folks are wondering about how final keyword plays in.
-
mjs over 2 years@BasilBourque "reassigning it discards potentially vital information" - then the implementor of that method should no reassign it. If they need the info, then they can just use another variable. they do not need final to prevent that. the java compiler knows whether something is going to be alterered or not, and need not you to tell it is final or not to save memory. if