Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why should I use the keyword "final" on a method parameter in Java?

People also ask

Why do we use final keyword in Java?

The final keyword is a non-access modifier used for classes, attributes and methods, which makes them non-changeable (impossible to inherit or override). The final keyword is useful when you want a variable to always store the same value, like PI (3.14159...). The final keyword is called a "modifier".

Why do we need final keyword?

The final keyword has a different purpose when applied to classes and methods. When we apply the final keyword to a class, then that class cannot be subclassed. When we apply it to a method, then that method cannot be overridden. There are no reported performance benefits of applying final to classes and methods.

What happens when we add a final keyword to a method?

When a method is declared with final keyword, it is called a final method. A final method cannot be overridden. The Object class does this—a number of its methods are final. We must declare methods with the final keyword for which we are required to follow the same implementation throughout all the derived classes.

Can final be used on method parameters and local variables?

In Java, you can qualify local variables and method parameters with the final keyword. Doing so results in not being able to reassign x and qwerty in the body of the method.


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.