185

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

Aly
  • 15,865
  • 47
  • 119
  • 191
  • 3
    @Joachim - actually it's the same as `const` in C! The difference is that in Java a "pointer" to an object doesn't carry any special `*` syntax. Hence the confusion here. The variable is const/final, the object it points to is not. – Daniel Earwicker Feb 10 '10 at 12:23
  • @Earwicker I think I take your point, but I think Joachim's is much more accurate in saying a 'final' method param has no implication for the caller, which is true, but not really what 'const' means in general. – Sean Owen Feb 10 '10 at 12:32
  • As an aside, I think you often see methods declared this way by people who believe, rightly, that it's clearer and less error-prone to not treat method params as local variables that can change. 'final' merely enforces this. – Sean Owen Feb 10 '10 at 12:32
  • @Earwicker: My C is weak. I thought I remembered that a `const` parameter forced every value that's passed in to come from a `const` variable as well. It seems that's wrong. Sorry. – Joachim Sauer Feb 10 '10 at 12:44
  • 1
    @Sean: _i_ often see it, because our eclipse formatter is set up to do so. it's an artifact of a whole concept which promotes coding in the most restricted way (w.r.t access modifiers and in general), so when you remove the restriction you need to do so explicitly. my 2 cents. – Asaf Feb 10 '10 at 13:34
  • @Joachim - the issue is whether the variable is self-contained or is a reference/pointer to something else. This is always explicit in C, but depends on the type in Java. In C, you decide if a pointer variable should be const, or the object it points to, or both. You can put `const` in various places to get the combination you want. `const Obj *p` makes the `Obj` immutable but lets you change `p` to point to a different `Obj`, whereas `Obj * const p` leaves the `Obj` mutable and locks down `p`. Lastly `const Obj * const p` makes both the pointer and the object immutable. – Daniel Earwicker Feb 10 '10 at 14:45
  • @DanielEarwicker: I believe it is more correct to say that `const` in C is similar to `final` in Java, but the semantics of the two keywords are not identical between languages. – scottb Aug 09 '13 at 23:00

9 Answers9

250

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.

Thirler
  • 20,239
  • 14
  • 63
  • 92
  • 77
    It certainly makes a copy (there is an optimization where the compiler doesn't make a copy, when there is no difference with making a copy). However you have to keep in mind that in the case of an object. The object really only is a reference to an object. So in that case you will get a copy of the reference. – Thirler Feb 10 '10 at 14:12
  • if I have final int and thread inside my method can I still change the value of this int parameter from another methods ? – Mohammed Subhi Sheikh Quroush Feb 21 '13 at 11:57
  • 25
    It really is irrelevant if the parameter's value is a copy of the argument's source or the same reference. The fact of the matter is that any variable is just a reference to the actual object in memory. Marking a parameter as final prohibits the reassignment of the parameter within the code block of the function. However, if the parameter is not final, although one can reassign the parameter from the passed in argument to anything else, the caller of the function never loses its reference, and continues to point to the same object. – Armand Feb 20 '14 at 18:19
  • 18
    for future readers, pls read http://javadude.com/articles/passbyvalue.htm instead of these answers. Java is pass-by-value and key word 'final' just cares that this object wont be changed by accident within the method. (Or for the reason to be used in anonymous classes) – huidube May 27 '15 at 12:47
  • 1
    Yes, Java passes-by-value and copies the object reference (which is a _pointer_ to an object). The final keyword then prevents the reference from being changed but ... any mutable members of said object can still be modified, despite the fact that the parent reference is a copy. See: http://www.javaworld.com/article/2077424/learn-java/does-java-pass-by-reference-or-pass-by-value.html – Darrell Teague Jun 20 '16 at 21:09
  • 6
    Java only copies the reference of the parameters, not the parameters themselves. This should be clarified in the answer. – Planky Apr 07 '17 at 21:32
  • Wow !! Please correct this ... object are passed by reference not by value, so objects pass a copy of the reference, not a new object .... Without this clarification this answer is very wrong. – Dan Ortega Feb 23 '21 at 22:08
  • 1
    @DanOrtega I added some clarification – Thirler Feb 26 '21 at 07:27
100

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.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 2
    What would be the effect of the change of the variable value (which is declared as final) on inner class ? – Tom Taylor Sep 30 '17 at 12:41
  • But still, public boolean doesStringStartsWithZero(String str) throws Exception { boolean result = str.startsWith("0"); str = "name"; } What's the difference between the above example (with inner anonymous class and this util method)? – Tom Taylor Sep 30 '17 at 18:56
64

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.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
58

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.

Erick G. Hagstrom
  • 4,873
  • 1
  • 24
  • 38
  • 3
    I happened to find this more like a convention in teams. There's really no right/wrong answer. However, I kinda agree to @Erick G. HagstromErick. Having `final` on methods parameters helps you understand the outgoings of the method at first glance, and draws some attention to those non-final parameters. – KareemJ Nov 24 '20 at 07:48
24

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...

Rahel Lüthy
  • 6,837
  • 3
  • 36
  • 51
  • That's a very good point. It addresses a slightly different point than I think the OP had in mind, as it's a special case of the requirement that variables in an enclosing scope that are referenced within an anonymous inner class must be final, but still it offers a good reason for at least some method parameters to be final. – Erick G. Hagstrom Jun 11 '15 at 21:03
  • 2
    It's not "Because the Runnable instance would outlive the method", though. This is true of any anonymous inner class. – Erick G. Hagstrom Jun 11 '15 at 21:04
  • 2
    Oh, and now in Java 8 we have the effectively final concept. – Erick G. Hagstrom Jun 11 '15 at 21:05
4

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.

SilentKnight
  • 13,761
  • 19
  • 49
  • 78
3

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

Draken
  • 3,134
  • 13
  • 34
  • 54
Roopam
  • 270
  • 2
  • 12
2

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

ttati
  • 417
  • 3
  • 9
0

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.

Kilian Foth
  • 13,904
  • 5
  • 39
  • 57
  • 1
    You may wish to reconsider this position. Java does not pass by value. the simple test for this, is instead of passing String as the argument (which is immutable), pass in a StringBuffer() StringBuffer sb = new StringBuffer("Hello"); addWord(sb); System.out.println(sb.toString()); public void addWord(StringBuffer buf) { buf.append(" world"); } Running this, you will see sb outputs "Hello World". This would not be possible if it was pass by value, it is pass by reference, where the reference is a copy. Although arguably it is possible if it's final that the reference may not be copied – Armand Feb 20 '14 at 18:39
  • 1
    @Armand Java is always (always!) pass-by-value. – stuXnet Jan 27 '15 at 11:31