Final Modifier for method arguments. What do you think? January 2nd, 2010
The IT industry today is sodden with TLAs like SOA, ESB… and FLAs like AJAX, SOAP and JUNK. i was thinking about refreshing myself with some fundamentals again. Blogging about a basic concept may not be cool, but refreshing – don’t you think? I know what you are thinking. You are thinking that i am digressing too much. Ok, lets cut to the chase.
One of the best practices i follow religiously is to use final modifiers for method arguments where applicable. This is “supposedly” a best-practice written by somebody somewhere. Regardless of whether it is documented as a best-practice or not it is an important concept to understand and use. I have 2 valid reasons to use them for my method arguments.
First, final variables cannot be modified. Come on, everybody knows that. Maybe, but its use is significantly enhanced when it is a method argument and more importantly when you are in a big team environment.
Lets assume that a method takes List as its argument. Typically, the intention of that method is to work with the List – add to it, remove elements from it, use its elements in some way, sort it and what not. Consequently when the method returns, the caller can investigate the passed List and work with the modifications the callee introduced. But the caller will be on for a big surprise if the callee changes the instance that reference points to itself.
We know that java uses “Pass by copy of reference”. If the callee points the received reference to a different List and then modifies this List, the caller will not be able to see any change at all. This is because the copy of the reference held by the caller still points to the same old List. More often than not this is done by mistake and is not intentional. If such a behavior is intentional, final modifier is not required. In all other cases since this leads to bugs in code, it is a good practice to use final modifier for method arguments.
Second, if the method uses the infamous anonymous inner-class syntax to do something, and that inner class wants to use the methods arguments, java requires those arguments to be declared final. This is more of a rule than a valid reason.
Are there more valid reasons? I will be glad to receive information from you guys.
The final keyword on a method parameter does not affect the caller of a method in any way whatsoever.
All a final method parameter enforces is that the method itself does not modify the reference. But, it makes no guarantee that methods or fields of that parameter will not be changed. So a final List can still be modified, and those changes will be reflected in the caller’s reference, just as with a non-final parameter.
@Craig: Thats exactly the point I am trying to make. If the caller expects the lists data to modified, but the callee mistakenly assigns the argument to a new List, then whatever modifications the callee makes to the List will not be visible to the caller.
Ah, that makes sense. I thought you were trying to indicate that making a parameter final ensured that a caller would not see any changes made to a passed-in object (like const in C++).
Here is some sample code to illustrate the problem better.
public static void main(String[] args) {
ArrayList> l = new ArrayList>();
l.add(“1″);
l.add(“2″);
l.add(“3″);
System.out.println(“Original List ” + l);
badtamper(l);
System.out.println(“In caller value after bad callee:” + l);
tamperlist(l);
System.out.println(“In caller value :” + l);
}
private static void badtamper(final ArrayList> l) {
ArrayList> nl = new ArrayList>();
nl.add(“One”);
nl.add(“Two”);
nl.add(“Three”);
l = nl;
System.out.println(“In bad callee value :” + l);
}
private static void tamperlist(ArrayList> l) {
l.remove(2);
l.add(2, “two”);
System.out.println(“In callee value :” + l);
}
Now when the code is run the following gets printed out :
Original List [1, 2, 3]
In bad callee value :[One, Two, Three]
In caller value after bad callee:[1, 2, 3]
In callee value :[1, 2, two]
In caller value :[1, 2, two]
And looking at the values, the problem becomes obvious.
To prevent it, if ‘final’ arguments are used then the editor can warn when an assignment is done for the variable that has been passed and thus prevent the unpleasant surprise, which most developers go thru in their learning curve and learn the hard way.
@Vinod: Good Illustration of the problem with the example.
You should only introduce additional syntactic clutter if it solves problems. I love to make object fields final because I do a lot of concurrent programming.
But making local variables final is solving a problem I haven’t seen happening.
If in Java by default all local variables where final and you need to do something special to mark them as updatable, I would not have a problem with it. But adding it to each variable explicitly makes code very verbose.
And it even gets more verbose if annotations are added.. like the @NotNull crap.
“If the caller expects the lists data to modified, but the callee mistakenly assigns the argument to a new List, then whatever modifications the callee makes to the List will not be visible to the caller.”
This tells me that the method is not being unit tested, syntactic changes will not change that and will not fix other bugs unit testing will also expose.
Personally I think the params should be final by default and I would reject code I review that modifies params as I have yet to see a case where it is justified.
@Steve It is a bad idea to use a unit test for something that the compiler can catch for you. If you do not rely on the compiler for finding potential bugs for you then why are you even using a statically typed language in the first place?
Imho a signature may be more clear while using the final keyword for parameters, but methods should not be so long that we cannot infer the immutability of a parameter by reading the method body.
+1 Peter Veentjer’s final members and non-final locals where possible
+1 Steve’s not to reassign params (locals)
As stated in the article, the ‘final’ keyword is necassary to mark parameters as ’semi-output’ parameters. The usual way to return a result in Java is to use a ‘return’ statement. So there shouldn’t be many ‘final’ parameters in Java code.
Java is missing real output parameters. C# has it’s ref- and out-parameters. You can reassign them in the callee and the caller will notice it because these parameters are references(-of-references).
Good job man..
Input params are not for output…
Sometimes you run across some code that makes you cringe a little bit. That happened to me today when I ran across this blog post. It’s about how the final modifier is used for method parameters. A sample of what the post is trying to convey look…
I fully agree with Peter Veentjer, with the addition that I think the lack of named parameters in Java is totally unrelated but similar problem.
I prefer to omit ‘final’ from method arguments, and use tools like Checkstyle to enforce rules such as not changing what method arguments refer to. Too much syntactic noise for my taste.
Final parameters and local variables can be used in inner classes. Non-final parameters and local variables cannot. Whether this is good or bad is arguable.
l = nl;
Using final to clutter up your code in an attempt to prevent lines like this is pure rubbish. If you are working for/with developers who make such rudimentary mistakes such as this I suggest you fire them or switch jobs.
If you really need a compiler to prevent you from making such mistakes you really have much bigger problems than finals. It’s absolutely pointless in java
So guys.
Vinod get us example and Ganeshji Marwaha says that it is good code, but lets look at the code.
private static void badtamper(final ArrayList l) {
ArrayList nl = new ArrayList();
nl.add(”One”);
nl.add(”Two”);
nl.add(”Three”);
l = nl; – THIS IS COMPILATION TIME ERROR – you can’t change reference if it is final, but you can change data in object
System.out.println(”In bad callee value :” + l);
}
Ok i can change some things:
public static void main(String[] args) {
ArrayList l = new ArrayList();
l.add(”1?);
l.add(”2?);
l.add(”3?);
System.out.println(”Original List ” + l);
badtamper(l);
System.out.println(”In caller value after bad callee:” + l);
tamperlist(l);
System.out.println(”In caller value :” + l);
}
private static void badtamper(final ArrayList l) {
l.remove(2);
l.add(2, “bad”);
System.out.println(”In bad callee value :” + l);
}
private static void tamperlist(ArrayList> l) {
l.remove(2);
l.add(2, “not bad”);
System.out.println(”In callee value :” + l);
}
Now when the code is run the following gets printed out :
Original List [1, 2, 3]
In bad callee value :[1, 2, bad]
In caller value after bad callee:[1, 2, bad]
In callee value :[1, 2, not bad]
In caller value :[1, 2, not bad]
Actually no difference.
[...] action, Warning, warning, the const decoration is dropped…, the same reason lies in the bool …Final Modifier for method arguments. What do you think? | GaneshThe IT industry today is sodden with TLAs like SOA, ESB… and FLAs like AJAX, SOAP and JUNK. i was [...]
Consequently when the method returns, the caller can investigate the passed List and work with the modifications the callee introduced.
cheap UGG boots
UGGS Shoes
ugg classic boots
uggs for cheap
ugg cardy
Chi Sale, Inc. is welcome here you will find cheap GHD Straightners Hair and Flat Iron Chi 50% -70% off GHD , CHI Straightners factory.All direct hair iron will be within a few days EMS factory work from home, where we live. sent to the UK We do our best to send more work in 5-7 days.Just find the cheapest products from CHI and GHD Straightener Hair, Inc. now.Designated trademarks and brands are the property of their respective owners.
Paul Smith Belts
Flat Iron Chi
discount mbt shoes
Thanks ! wansantg2zxy.