This question already has answers here:
Why Final is used in method parameters [duplicate]
(6 answers)
Why should I use the keyword "final" on a method parameter in Java?
(12 answers)
Closed 5 years ago.
So I can fully understand why you may want to make your class final. Imagine String class not being final, and you have a library, in which you have a method that takes a String as an argument and depends on the length() method for some operation, but someone extends the String class and overrides the length to return -1 always..
But I can not figure out why anyone would ever declare a parameter of a method final. Java is pass by value anyway, so if the parameter is a primitive, it is already final (in a sense).. And if you are passing a Reference Type does it guarantee anything to the caller of the method? I do not think so..
void foo(final List<Object> o) {
o.add(new Object());
} // oops?
So final prevents the following:
void foo(final List<Object> o) {
o = new ArrayList();
}
But why would I ever want to do this anyway? I can always create a new variable, and it does not assign a new Object to the caller 's variable anyway? (I mean, I can not change what the callers reference refers to anyway, even if the parameter was not declared final..)
My question is, what is the purpose of a final parameter in a method declaration? Is it for the caller? Does it guarantee anything?
I also find strange that the following will compile fine:
public interface MyInterface {
void foo(final Object o);
}
class MyImpl implements MyInterface {
#Override
public void foo(Object o) { // final in interface, not final in impl..
}
}
but maybe it will make sense once I understand the main question I have.
Sometimes, it helps the fellow programmers or maintenars that they should not change the value of that variable.
Ex: Imagine a method taking a string parameter. Imagine that it a very long method having 1000 lines of code. If the parameter is not marked as final, the second programmer see an opportunity of changing the value in it. The first programmer resumes the work on the method while not having the knowledge that the variable is assigned a new value.
Making it final will fully assure the first programmers intention to be passed on to second.
Apart from this, if you need to use this variable in any of anonymous class in that method, you can't use it unless it is final.
Hope this helps.
It doesn't guarantee anything to the caller either way (regardless whether the argument is a primitive type or a reference type).
A method argument is a local variable whose value is initialized by the caller of the method. Making it final means the body of the method cannot assign a new value to that variable locally, so it only makes a different within the body of the method (since assigning a new value to such a variable within the method body would make no different for the caller of the method).
It ensures that any code in the method's body that uses the value of the argument would use the original value passed by the caller and not some different value that was assigned to it within the method body.
Related
Consider this class:
public class Passenger {
public Passenger() {
}
public Passenger(int freeBags) {
this(freeBags > 1 ? 25.0d : 50.0d);
this.freeBags = freeBags;
}
public Passenger(int freeBags, int checkedBags) {
this(freeBags);
this.checkedBags = checkedBags;
}
private Passenger(double perBagFee) {
this.perBagFee = this.perBagFee;
}
}
Passenger fred = new Passenger(2);
If I understand correctly, 'fred' is a new instance of Passenger. 'fred' calls the constructor with one parameter which is public Passgener(int freeBags). Then this line this(freeBags > 1 ? 25.0d : 50.0d) gets called.
Here is my question: How does the compiler know that the conditional statement in the first constructor to chain to the 'private' constructor? My guess would be that the 'd' in the conditional statement points to the double parameter in the private constructor. But what if there was another constructor with a double parameter? What would it chain to then? There is no mention of perBagFee in the first constructor. I'm a little confused.
EDIT
How does the compiler know that the conditional statement in the first constructor to chain to the 'private' constructor?
Since either values returned by your ternary expression are double values, the compiler knows that this call refers to your constructor method that received one double argument.
My guess would be that the 'd' in the conditional statement points to the double parameter in the private constructor.
The .0d suffix merely says that those are double values.
There is no mention of perBagFee in the first constructor
Method arguments names have no relevance whatsoever outside the method itself. The compiler will always check for what kind of object does your expression evaluate to in order to figure out which method you want to call.
But what if there was another constructor with a double parameter?
Try it :) Inside the same class, you cannot define two methods (constructor or not) with the same signature, regardless of the visibility. Official docs on methods overloading:
Overloaded methods are differentiated by the number and the type of the arguments passed into the method.
You cannot declare more than one method with the same name and the same number and type of arguments, because the compiler cannot tell them apart.
What you can see is called Overloading
Overloading is a concept used to avoid redundant code where the same
method name is used multiple times but with a different set of
parameters. The actual method that gets called during runtime is
resolved at compile time, thus avoiding runtime errors.
Java does not remember variable names of the method to identify which overloaded constructor to be called, instead, Java tries to match the variable type
Passenger(int) -> Passenger(10)
Passenger(int, int) -> Passenger(10,10)
Passenger(double) -> Passenger(2.5d)
so, if you defined another constructor of the same pattern as Passenger(double)
. Java will throw compile time error
constructor Passenger(double) is already defined in class Passenger
I couldn't find information if it is possible to write public void in constructor section. Is it possible?
At the byte code level, a constructor is always void so it would be redundant to specify it. i.e. the constructor is always called <init>V i.e. the V is the return type where V == void. Similarly the static initialiser is <clinit>V You will see this notation if you take a stack trace (e.g. print an exception) while in these methods.
The constructor actually takes the object to be initialised as an argument as the object is created before calling the constructor. Note: you can create the object without calling a constructor with Unsafe.allocateInstance(Class)
I couldn't find information if it is possible to write public void in constructor section. Is it possible?
It is not possible to write it as Java distinguishes a constructor from a method is that it must have the same name as the class, and it must not specify a return type. If you specify a return type, it assumes it's a method.
The notation x = new Clazz() also limits the number of return values to 1 which is the object. There is no easy way to modify this notation to return more than one object. i.e. supporting a return type for constructors would not be easy.
If you want to define a return type, most likely you are thinking of a factor method like this.
public static MyInterface createObject() {
return new MyClass();
}
Note how the return type is different to the class actually created, but there is still only one reference returned.
The constructor syntax is defined in the Java Language Specification. Anything else is incorrect.
The question is unclear. Peter Lawrey answered one interpretation, this is an answer to another.
You cannot declare methods within a constructor. You can, however, declare a class and declare variables.
Because you are able to declare a class within a constructor, you could declare a method inside of a class and then use the class. If the method isn't static you can construct an object of the class.
No, Java only allows a method to be declared within a class, not within another method or constructor.Indirectly you can do something like this :
public A() {
class B {
public void m() {
}
}
}
I have a method that uses a SwingWorker. Part of the code is shown below:
public class mySocket {
public void writePacket(final String packet) {
// schedules execution on the single thread of the executor (so only one
// background operation can happen at once)
//
executor.execute(new SwingWorker<String, Void>() {
#Override
protected String doInBackground() throws Exception {
// called on a background thread
System.out.println("writing out this packet->" + packet + "
<-");
out.println(packet);
String thePacket = readPacket();
return thePacket;
}
..................
My questions are about the signature of the writePacket method. The variable packet must be declared final or the compiler complains because SwingWorker is an inner class. This raises the following questions about how and when I can assign values to this variable:
Final to me means that the variable can only be assigned a value once. But because the declaration is part of the signature of a method, I don't know what this means in this context.
I always assumed that final variables were assigned values when the class was instantiated but here it is assigned when the method is called. Does the variable passed to the method also need to be declared final and assigned in the class's constructor for this to work?
Can I call the method more than once with different values for packet or because the variable is declared final, does this mean that if I want to call the method with different values, I need to reinstantiate the class for each new value of the variable packet ?
Thanks in advance for your help.
Elliott
1. Final to me means that the variable can only be assigned a value once. But because the declaration is part of the signature of a method, I don't know what this means in this context.
It just means that you can't reassign a new value to the variable packet.
2. I always assumed that final variables were assigned values when the class was instantiated but here it is assigned when the method is called. Does the variable passed to the method also need to be declared final and assigned in the class's constructor for this to work?
You can have local final variables as well. Same rules applies, but they are unrelated to constructor / this reference.
3. Can I call the method more than once with different values for packet or because the variable is declared final, does this mean that if I want to call the method with different values, I need to reinstantiate the class for each new value of the variable packet ?
You can call the method several times with different values. The packet variable is like a local variable. and No, you don't need to reinstantiate the class for each value / call.
Further SO reading:
Cannot refer to a non-final variable inside an inner class defined in a different method
Cannot refer/modify non-final variable in an innerclass
access to variable within inner class in java
The inner class can only reference final variables because the variable that is wantd is actually passed to the inner class ctor as a parameter. If the variable was not final, and changed after the inner class was created, it would no longer be holding onto the current but previous variable. To avoid such strangeness and to keep things simple, variables/parameters must be final for an inner class to read.
Final to me means that the variable can only be assigned a value
once. But because the declaration is part of the signature of a
method, I don't know what this means in this context.
It means the same thing, you can't re-assign the variable.
// this compiles
public void foo(String bar){
bar = "xyz";
}
// this doesn't
public void foo(final String bar){
bar = "xyz";
}
I always assumed that final variables were assigned values when
the class was instantiated but here it is assigned when the method is called.
No, local variables can also be final, and parameters too. They are assigned once per scope (block or method level).
Does the variable passed to the method also need to be
declared final and assigned in the class's constructor for this to
work?
No, that's totally irrelevant
Can I call the method more than once with different values for packet
or because the variable is declared final, does this mean that if I
want to call the method with different values, I need to reinstantiate
the class for each new value of the variable packet ?
No, see above. It's a new variable for each method call.
Final to me means that the variable can only be assigned a value once. But because the declaration is part of the signature of a method, I don't know what this means in this context.
Same thing. It means you cannot re-assign a new value to the local variable that contains the parameter (that is considered bad practice anyway).
I always assumed that final variables were assigned values when the class was instantiated but here it is assigned when the method is called
That first part is true for final instance variables, not for local variables.
But the idea is the same: They need to be assigned a value and it can happen only once.
Can I call the method more than once with different values for packet or because the variable is declared final, does this mean that if I want to call the method with different values, I need to reinstantiate the class for each new value of the variable packet ?
You can call it many times. The parameter being declared final has no impact to code calling of the method (just for its implementation).
This question already has answers here:
Why should I use the keyword "final" on a method parameter in Java?
(12 answers)
Closed 7 years ago.
I often encounter methods which look like the following:
public void foo(final String a, final int[] b, final Object1 c){
}
What happens if this method is called without passing it final parameters. i.e. an Object1 that is later changed (so is not declared as final) can be passed to this method just fine
Java always makes a copy of parameters before sending them to methods. This means the final doesn't mean any difference for the calling code. This only means that inside the method the variables can not be reassigned.
Note that if you have a final object, you can still change the attributes of the object. This is because objects in Java really are pointers to objects. And only the pointer is copied (and will be final in your method), not the actual object.
There is a circumstance where you're required to declare it final —otherwise it will result in compile error—, namely passing them through into an anonymous class or a lambda. Here's a basic example using an anonymous class:
public FileFilter createFileExtensionFilter(final String extension) {
FileFilter fileFilter = new FileFilter() {
public boolean accept(File file) {
return file.getName().endsWith(extension);
}
};
// Imagine what would happen when we're allowed to change extension here?
// extension = "foo";
return fileFilter;
}
And here's the exact same example in lambda flavor:
public FileFilter createFileExtensionFilter(final String extension) {
FileFilter fileFilter = file -> file.getName().endsWith(extension);
// Imagine what would happen when we're allowed to change extension here?
// extension = "foo";
return fileFilter;
}
Removing the final modifier would result in compile error, because it isn't guaranteed anymore that the value is a runtime constant. Changing the value after creation of the anonymous class or lambda would namely cause the instance of the anonymous class or lambda to behave different after the moment of creation.
Java is only pass-by-value. (or better - pass-reference-by-value)
So the passed argument and the argument within the method are two different handlers pointing to the same object (value).
Therefore if you change the state of the object, it is reflected to every other variable that's referencing it. But if you re-assign a new object (value) to the argument, then other variables pointing to this object (value) do not get re-assigned.
The final keyword on a method parameter means absolutely nothing to the caller. It also means absolutely nothing to the running program, since its presence or absence doesn't change the bytecode. It only ensures that the compiler will complain if the parameter variable is reassigned within the method. That's all. But that's enough.
Some programmers (like me) think that's a very good thing and use final on almost every parameter. It makes it easier to understand a long or complex method (though one could argue that long and complex methods should be refactored.) It also shines a spotlight on method parameters that aren't marked with final.
Consider this implementation of foo():
public void foo(final String a) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
System.out.print(a);
}
});
}
Because the Runnable instance would outlive the method, this wouldn't compile without the final keyword -- final tells the compiler that it's safe to take a copy of the reference (to refer to it later). Thus, it's the reference that's considered final, not the value. In other words: As a caller, you can't mess anything up...
final means you can't change the value of that variable once it was assigned.
Meanwhile, the use of final for the arguments in those methods means it won't allow the programmer to change their value during the execution of the method.
This only means that inside the method the final variables can not be reassigned.
final keyword in the method input parameter is not needed. Java creates a copy of the reference to the object, so putting final on it doesn't make the object final but just the reference, which doesn't make sense
If you declare any parameter as final, you cannot change the value of it.
class Bike11 {
int cube(final int n) {
n=n+2;//can't be changed as n is final
n*n*n;
}
public static void main(String args[]) {
Bike11 b=new Bike11();
b.cube(5);
}
}
Output: Compile Time Error
For more details, please visit my blog: http://javabyroopam.blogspot.com
Strings are immutable, so actully you can't change the String afterwards (you can only make the variable that held the String object point to a different String object).
However, that is not the reason why you can bind any variable to a final parameter. All the compiler checks is that the parameter is not reassigned within the method. This is good for documentation purposes, arguably good style, and may even help optimize the byte code for speed (although this seems not to do very much in practice).
But even if you do reassign a parameter within a method, the caller doesn't notice that, because java does all parameter passing by value. After the sequence
a = someObject();
process(a);
the fields of a may have changed, but a is still the same object it was before. In pass-by-reference languages this may not be true.
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;
}
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.➥ Add final 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;
}
}
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.
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?"
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.
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.
Using final in a method parameter has nothing to do with what happens to the argument on the caller side. It is only meant to mark it as not changing inside that method. As I try to adopt a more functional programming style, I kind of see the value in that.
Personally I don't use final on method parameters, because it adds too much clutter to parameter lists.
I prefer to enforce that method parameters are not changed through something like Checkstyle.
For local variables I use final whenever possible, I even let Eclipse do that automatically in my setup for personal projects.
I would certainly like something stronger like C/C++ const.
Since Java passes copies of arguments I feel the relevance of final is rather limited. I guess the habit comes from the C++ era where you could prohibit reference content from being changed by doing a const char const *. I feel this kind of stuff makes you believe the developer is inherently stupid as f*** and needs to be protected against truly every character he types. In all humbleness may I say, I write very few bugs even though I omit final (unless I don't want someone to override my methods and classes). Maybe I'm just an old-school dev.
Short answer: final helps a tiny bit but... use defensive programming on the client side instead.
Indeed, 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.
I never use final in a parameter list, it just adds clutter like previous respondents have said. Also in Eclipse you can set parameter assignment to generate an error so using final in a parameter list seems pretty redundant to me.
Interestingly when I enabled the Eclipse setting for parameter assignment generating an error on it caught this code (this is just how I remember the flow, not the actual code. ) :-
private String getString(String A, int i, String B, String C)
{
if (i > 0)
A += B;
if (i > 100)
A += C;
return A;
}
Playing devil's advocate, what exactly is wrong with doing this?
One additional reason to add final to parameter declarations is that it helps to identify variables that need to be renamed as part of a "Extract Method" refactoring. I have found that adding final to each parameter prior to starting a large method refactoring quickly tells me if there are any issues I need to address before continuing.
However, I generally remove them as superfluous at the end of the refactoring.
Follow up by Michel's post. I made myself another example to explain it. I hope it could help.
public static void main(String[] args){
MyParam myParam = thisIsWhy(new MyObj());
myParam.setArgNewName();
System.out.println(myParam.showObjName());
}
public static MyParam thisIsWhy(final MyObj obj){
MyParam myParam = new MyParam() {
#Override
public void setArgNewName() {
obj.name = "afterSet";
}
#Override
public String showObjName(){
return obj.name;
}
};
return myParam;
}
public static class MyObj{
String name = "beforeSet";
public MyObj() {
}
}
public abstract static class MyParam{
public abstract void setArgNewName();
public abstract String showObjName();
}
From the code above, in the method thisIsWhy(), we actually didn't assign the [argument MyObj obj] to a real reference in MyParam. In instead, we just use the [argument MyObj obj] in the method inside MyParam.
But after we finish the method thisIsWhy(), should the argument(object) MyObj still exist?
Seems like it should, because we can see in main we still call the method showObjName() and it needs to reach obj. MyParam will still use/reaches the method argument even the method already returned!
How Java really achieve this is to generate a copy also is a hidden reference of the argument MyObj obj inside the MyParam object ( but it's not a formal field in MyParam so that we can't see it )
As we call "showObjName", it will use that reference to get the corresponding value.
But if we didn't put the argument final, which leads a situation we can reassign a new memory(object) to the argument MyObj obj.
Technically there's no clash at all! If we are allowed to do that, below will be the situation:
We now have a hidden [MyObj obj] point to a [Memory A in heap] now live in MyParam object.
We also have another [MyObj obj] which is the argument point to a [Memory B in heap] now live in thisIsWhy method.
No clash, but "CONFUSING!!" Because they are all using the same "reference name" which is "obj".
To avoid this, set it as "final" to avoid programmer do the "mistake-prone" code.