459

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;
}
8
  • 120
    One quick point on terminology - Java doesn't have pass-by-reference at all. It has pass reference by value which is not the same thing. With true pass by reference semantics the results of your code would be different.
    – Jon Skeet
    Commented Feb 1, 2009 at 13:31
  • 10
    What's the difference between pass by reference and pass reference by value? Commented Oct 14, 2013 at 15:38
  • 1
    It's easier to describe that difference in a C context (at least for me). If I pass a pointer to a method like: <code>int foo(int bar)</code>, then that pointer is being passed by value. Meaning it is copied, so if I do something inside that method like <code>free(bar); bar = malloc(...);</code> then I've just done a really bad thing. The free call will actually free up the chunk of memory being pointed at (so whatever pointer I passed in is now dangling). However, <code>int foo(int &bar)</bar> means that code is valid and the value of the pointer passed in will be changed.
    – jerslan
    Commented Oct 15, 2013 at 20:18
  • 4
    The first one is supposed to be int foo(int* bar) and the last one int foo(int* &bar). The latter is passing a pointer by reference, the former is passing a reference by value.
    – jerslan
    Commented Oct 15, 2013 at 20:26
  • 3
    @Martin, in my opinion, it's a good question; see the title for the question, and the post content as an explanation for why the question is asked. Maybe I am misunderstanding the rules here, but this is exactly the question I wanted when searching for "uses of final parameters in methods". Commented Jun 15, 2016 at 11:52

12 Answers 12

348

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 be 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;
    }
}
26
  • 32
    "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. Commented Nov 27, 2013 at 8:07
  • 61
    @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. Commented Nov 27, 2013 at 21:07
  • 10
    @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? Commented Apr 10, 2014 at 12:40
  • 16
    Using message = ( msg || 'Hello World"' ) risks me later accidentally using msg. 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). Commented Mar 22, 2015 at 12:44
  • 10
    @BeniCherniavsky-Paskin the risk you describe is only because of the similarity between message and msg. But if he would call it something like processedMsg 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. ;)
    – Nir Alfasi
    Commented May 13, 2016 at 22:10
239

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.

8
  • 70
    btw you will see warning "The assignment to variable test has no effect" anyway
    – AvrDragon
    Commented Apr 4, 2012 at 16:03
  • 14
    @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. Commented Apr 30, 2013 at 9:49
  • 11
    @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.
    – arkon
    Commented May 28, 2013 at 9:11
  • 26
    @b1naryatr0phy actually it's a compiler warning, not just IDE-tip
    – AvrDragon
    Commented May 28, 2013 at 9:18
  • 10
    @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. Commented Nov 11, 2015 at 13:35
131

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?"

7
  • 19
    But to paraphrase Krusty with his danish, what have they done for us LATELY? =) Commented Feb 5, 2009 at 15:37
  • Yuval. That's funny! I guess peace can happen even if it is enforced by sword blade! Commented Aug 2, 2012 at 17:55
  • 2
    The 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. Commented Oct 14, 2013 at 15:40
  • 2
    "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)! Commented Nov 11, 2015 at 12:05
  • 1
    @SarthakMittal: The value won't be copied unless you actually use it, if that's what you're wondering.
    – Jon Skeet
    Commented Sep 18, 2017 at 7:32
80

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.

9
  • 1
    You lost me from "But if they are not final...." Can you put try to rephrase it, Maybe I haven't had enough cofee.
    – hhafez
    Commented Feb 2, 2009 at 5:45
  • 1
    You 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. Commented Feb 2, 2009 at 10:40
  • It doesn't make a copy, it is simply a reference to whatever object was referenced.
    – vickirk
    Commented Feb 10, 2010 at 13:40
  • 1
    @vickirk: sure it makes a copy - of the reference, in case of reference types. Commented Feb 10, 2010 at 14:12
  • Btw 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?
    – Pacerier
    Commented Nov 17, 2011 at 12:34
29

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.

3
  • 4
    I 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 Commented May 11, 2011 at 16:39
  • It's been a long time, but could you provide an example of the bug you caught?
    – user949300
    Commented Sep 27, 2017 at 6:05
  • See the most voted for answer. That has a really good example where the member variable is not set and instead the parameter is mutated. Commented Sep 27, 2017 at 22:21
20

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.

1
  • 3
    Exactly, 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. Commented Mar 22, 2015 at 12:53
11

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.

1
  • Not 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. Commented Dec 5, 2016 at 17:34
4

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.

6
  • 2
    "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.
    – Madbreaks
    Commented Apr 11, 2018 at 1:06
  • Please research before posting... stackoverflow.com/questions/40480/… Commented Apr 12, 2018 at 15:31
  • Simply 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. Commented Apr 12, 2018 at 15:32
  • Either 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
    Commented Apr 12, 2018 at 16:39
  • Downvoting because op asked why use final, and you gave just one, incorrect reason.
    – Madbreaks
    Commented Apr 12, 2018 at 16:46
4

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.

2

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?

1
  • Be 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. Commented Aug 13, 2018 at 17:52
0

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.

-1

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:

  1. We now have a hidden [MyObj obj] point to a [Memory A in heap] now live in MyParam object.
  2. 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.