132

Java allows marking variables (fields / locals / parameters) as final, to prevent re-assigning into them. I find it very useful with fields, as it helps me quickly see whether some attributes - or an entire class - are meant to be immutable.

On the other hand, I find it a lot less useful with locals and parameters, and usually I avoid marking them as final even if they will never be re-assigned into (with the obvious exception when they need to be used in an inner class). Lately, however, I've came upon code which used final whenever it can, which I guess technically provides more information.

No longer confident about my programming style, I wonder what are other advantages and disadvantages of applying final anywhere, what is the most common industry style, and why.

gnat
  • 21,442
  • 29
  • 112
  • 288
Oak
  • 5,215
  • 6
  • 28
  • 39
  • @Amir coding-style questions just seem to belong here better than on SO, and I couldn't find any policy in the FAQ or on this site's meta regarding this. Can you please direct me? – Oak Feb 16 '11 at 09:12
  • 1
    @Oak It says: "Specific programming problem, software algorithms, **coding**, ask on Stack Overflow" – Amir Rezaei Feb 16 '11 at 09:20
  • 8
    @Amir I disagree, I don't see how this is a coding problem. In any case this debate does not belong here, so I've opened a [meta-topic on this issue](http://meta.programmers.stackexchange.com/questions/1179/are-coding-style-questions-that-deal-with-language-specific-features-allowed). – Oak Feb 16 '11 at 09:32
  • I find myself wishing C# had something equivalent because it would make some manual refactoring much easier. – Peter Taylor Feb 16 '11 at 09:47
  • @Oak http://programmers.stackexchange.com/questions/48419/method-chaining-vs-encapsulation is a coding style question. This question is bound to language specific feature. – Amir Rezaei Feb 16 '11 at 09:51
  • duplicate of http://stackoverflow.com/questions/3559133/everythings-final –  Feb 16 '11 at 09:55
  • To reiterate my answer on the meta-discussion question, it's perfectly within the domain of Programmers.SE: answers are entirely based on convention derived from experience. Additionally, it would be entirely off-topic on Stack Overflow, which would be interested in a specific problem you were having, not a programming philosophy/best practices question. –  Feb 16 '11 at 10:07
  • @Mark "answers are entirely based on convention derived from experience" do you mean that answer decides if a question right or wrong? – Amir Rezaei Feb 16 '11 at 10:32
  • @Amir the quality and character of answers absolutely determines the usefulness of a question. Check out [Good Subjective, Bad Subjective](http://blog.stackoverflow.com/2010/09/good-subjective-bad-subjective/) for more information. –  Feb 16 '11 at 10:34
  • @Mark So if one asks a good question and the answer are bad then what? IMO it should be the other way around. – Amir Rezaei Feb 16 '11 at 10:38
  • @Amir if a question can't elicit constructive answers, it's not a good question. Again, check out the article I linked which explains the rationale in detail. –  Feb 16 '11 at 10:40
  • 7
    @amir this is totally on topic for this site, as it is a subjective question about programming -- please see the /faq – Jeff Atwood Feb 16 '11 at 18:03
  • @Jeff This question was closed and now it’s reopend. It shows that not everyone agrees with the definitions. – Amir Rezaei Feb 16 '11 at 19:30
  • @Jeff @Mark @Oak This question is already asked at SO, so what is the point of reopening it? stackoverflow.com/questions/3559133/everythings-final – Amir Rezaei Feb 17 '11 at 07:45
  • @amir perhaps but those all predate programmers, and are all subjective "almost no code" whiteboard-y discussions, of the type we encourage here and not on SO – Jeff Atwood Feb 17 '11 at 07:54
  • 1
    Re, local variables: Older Java compilers paid attention to whether you declared a local `final` or not, and optimized accordingly. Modern compilers are smart enough to figure it out for themselves. At least on local variables, `final` is strictly for the benefit of human readers. If your routines are not too complicated, then most human readers should be able to figure it out for themselves too. – Solomon Slow Aug 31 '16 at 15:46
  • Java specification allows aggressive optimization of final fields. Within a thread, it is permissible to reorder reads of a final field after the constructor has finished. https://stackoverflow.com/a/3301720/9465588 Your code can be more efficient declaring final fields when you can, if the VM decides so. – DGoiko Jan 28 '20 at 21:10
  • @DGoiko this question is explicitly about locals and parameters, not fields. – Oak Jan 28 '20 at 21:27

5 Answers5

87

I use final the same way as you. To me it looks superfluous on local variables and method parameters, and it doesn't convey useful extra information.

One important thing is that strive to keep my methods short and clean, each doing a single task. Thus my local variables and parameters have a very limited scope, and are used only for a single purpose. This minimizes the chances of reassigning them inadvertently.

Moreover, as you surely know, final doesn't guarantee that you can't change the value/state of a (nonprimitive) variable. Only that you can't reassign the reference to that object once initialized. In other words, it works seamlessly only with variables of primitive or immutable types. Consider

final String s = "forever";
final int i = 1;
final Map<String, Integer> m = new HashMap<String, Integer>();

s = "never"; // compilation error!
i++; // compilation error!
m.put(s, i); // fine

This means that in many cases it still doesn't make it easier to understand what happens inside the code, and misunderstanding this may in fact cause subtle bugs which are hard to detect.

Péter Török
  • 46,427
  • 16
  • 160
  • 185
  • 3
    Regarding the edit - I'm aware of the semantics of `final`, thank you :) but good point about short & clean methods - I guess that if the method is short enough that it's obvious a variable isn't being re-assigned into, there's even less motive for considering the `final` keyword. – Oak Feb 16 '11 at 10:35
  • Wouldn't it be great if we could have final parameters & local variables, and still a short and clean syntax? http://programmers.stackexchange.com/questions/199783/java-how-to-make-local-fields-parameters-final-without-having-a-final-keywo – oberlies May 29 '13 at 13:05
  • 10
    "final doesn't guarantee that you can't change the value/state of a (nonprimitive) variable. Only that you can't reassign the reference to that object once initialized." Nonprimitive = reference (the only types in Java are primitive types and reference types). The value of a variable of reference type *is* a reference. Therefore, you can't reassign the reference = you can't change the value. – user102008 Dec 05 '15 at 00:12
  • 2
    +1 for the reference/state pitfall. Note though that marking variables final may be necessary to create closures in Java8's new functionnal aspects – Newtopian Aug 26 '16 at 14:22
  • Your comparison is biased as @user102008 pointed out. Variable assignment is not the same as its value update – ericn Oct 05 '18 at 04:11
  • Keep in mind that with reflection you can actually change that reference aswell (but you should not! https://stackoverflow.com/a/3301720/9465588) – DGoiko Jan 28 '20 at 21:00
  • Ok, I will use `final`. The reason being it communicates my intention for the code even if my code never actually tries to re-assign anything. – djangofan Sep 09 '22 at 22:21
82

Your Java programming style and thoughts are fine - don't need to doubt yourself there.

On the other hand, I find it a lot less useful with locals and parameters, and usually I avoid marking them as final even if they will never be re-assigned into (with the obvious exception when they need to be used in an inner class).

This is exactly why you should use the final keyword. You state that YOU know it'll never be re-assigned, but no one else knows that. Using final immediately disambiguates your code that tiny bit more.

J.K.
  • 13,063
  • 1
  • 40
  • 56
  • 16
    If your method is clear and does only one thing the reader will know too. Final word only makes the code unreadable. And if its unreadable its much more ambiguous – eddieferetro Mar 03 '16 at 14:46
  • 11
    @eddieferetro Disagreed. The keyword `final` states intent, which makes the code more readable. Also, once you must deal with real-world code, you'll notice it's seldom pristine and clear, and liberally adding `final`s everywhere you can will help you spot bugs and understand legacy code better. – Andres F. Aug 26 '16 at 02:21
  • 10
    Is the "intent" that the variable will never change, and that *your code relies on that fact*? Or is the intent "it just so happens that this variable never changes so I'm marking it final". The later is useless and possibly harmful noise. And since you seem to advocate marking *all* the locals, you are doing the later. Big -1. – user949300 Aug 26 '16 at 04:19
  • 3
    `final` states intent, which is usually a good thing in a piece of code, but it comes at the price of adding visual clutter. Like most things in programming, there is a trade-off here: is expressing the fact your variable is only going to be used only once worth the added verbosity? – christopheml Oct 11 '17 at 08:30
  • 2
    The visual clutter will be greatly reduced when using syntax highlighting. I mark my locals that are assigned only once - and that I want to be assigned to only once - with `final`. That may be **most** of the locals, but clearly **not all**. For me there is no "happens to never change". There are 2 clearly separated kinds of locals in my world. Those that aren't ever supposed to change again (final) and those that must change as a result of what the task at hand dictates (of which there are very little, making the functions pretty easy to reason about). – blubberdiblub Oct 23 '19 at 14:50
  • Except it really doesn't do that - no in a useful way. What you really want is an immutable marker, which doesn't exist. You can pass a final object, and call all the setters you like; java won't stop you, which honestly, makes final pretty much useless. Also - reassigning the input parameters is bad, but mutating the object passed in is worse. reassigning the name of the variable, honestly, if you're method is short; you won't ever do that anyway; so again - useless. – PlexQ Jul 04 '20 at 18:33
41

One advantage of using final / const wherever possible is that it reduces the mental load for readers of your code.

Readers are assured that the value / reference is never altered later on. So developers need not pay attention to modifications in order to understand the computation.

I've have changed my mind regarding this after learning pure-functional programming languages. It's a relief knowing you can trust that a "variable" always holds its initial value.

marstato
  • 4,538
  • 2
  • 15
  • 30
LennyProgrammers
  • 5,649
  • 24
  • 37
  • 22
    Well, in Java `final` doesn't guarantee that you can't change the value/state of a (nonprimitive) variable. Only that you can't reassign the _reference_ to that object once initialized. – Péter Török Feb 16 '11 at 09:35
  • 9
    I know, that's why i distinguished between value and reference. The concept is the most useful in the context of immutable data structures and/or pure-functionality. – LennyProgrammers Feb 16 '11 at 11:07
  • 7
    @PéterTörök It's immediately helpful with primitive types, and somewhat helpful with references to mutable objects (at least you know you're always dealing with the same object!). It's immensely helpful when dealing with code designed to be immutable from the ground up. – Andres F. Aug 26 '16 at 02:23
  • For method parameters I would say it increases the mental load due to worse readability. For me parameters are not assigned in a method by default. I don't need a final for that. If a parameter IS reassigned it is the very rare exception and I expect the code to make that VERY clear. – Nils Rommelfanger Feb 04 '21 at 11:14
27

I consider final in method parameters and local variables to be code noise. Java method declarations can be quite long (especially with generics) - there's no need to make them any longer.

Unit tests can cover that

If unit tests are written properly, assigning to parameters that is "harmful" will be picked up, so it should never actually be a problem. Visual clarity is more important than avoiding a possible bug that isn't picked up because your unit tests have insufficient coverage.

Static code analysis can help

Tools like Sonar, FindBugs and CheckStyle can be configured to break the build if assignment is made to parameters or local variables, if you deeply care about such things.

Use in anonymous class

Of course, if you need to make them final, for example because you're using the value in an anonymous class, then no problem - that's the simplest cleanest solution.

Strive for readable code that is simple

Apart from the obvious effect of adding extra keywords to your parameters, and thereby IMHO camouflaging them, adding final to method parameters can often make the code in the method body become less readable, which makes the code worse - to be "good", code must be as readable and as simple as possible. For a contrived example, say I have a method that needs to work case insensitively.

Without final:

public void doSomething(String input) {
    input = input.toLowerCase();
    // do a few things with input
}

Simple. Clean. Everybody knows what's going on.

Now with 'final', option 1:

public void doSomething(final String input) {
    final String lowercaseInput = input.toLowerCase();
    // do a few things with lowercaseInput
}

While making the parameters final stops the coder adding code further down from thinking he's working with the original value, there's an equal risk that code further down may use input instead of lowercaseInput, which it shouldn't and which can't protected against, because you can't take it out of scope (or even assign null to input if that would even help anyway).

With 'final', option 2:

public void doSomething(final String input) {
    // do a few things with input.toLowerCase()
}

Now we're just created even more code noise and introduced a performance hit of having to invoke toLowerCase() n times.

With 'final', option 3:

public void doSomething(final String input) {
    doSomethingPrivate(input.toLowerCase());
}

/** @throws IllegalArgumentException if input not all lower case */
private void doSomethingPrivate(final String input) {
    if (!input.equals(input.toLowerCase())) {
        throw new IllegalArgumentException("input not lowercase");
    }
    // do a few things with input
}

Code Noise

Talk about code noise. This is a train wreck. We've got a new method, a required exception block, because other code may invoke it incorrectly. More unit tests to cover the exception. All to avoid one simple, and IMHO preferable and harmless, line.

There's also the issue that methods should not be so long that you can't easily visually take it in and know at a glance that an assignment to parameter has taken place.

I do think it is good practice/style that if you assign to a parameter you do it every early in the method, preferably first line or straight after basic input checking, effectively replacing it for the entire method, which has a consistent effect within the method. Readers know to expect any assignment to be obvious (near the signature declaration) and in a consistent place, which greatly mitigates the problem that adding final is trying to avoid. Actually I rarely assign to parameters, but if I do I always do it at the top of a method.


Note also that final doesn't actually protect you like it may at first seem:

public void foo(final Date date) {
    date.setTime(0); 
    // code that uses date
}

final doesn't completely protect you unless the parameter type is primitive or immutable.

hc_dev
  • 131
  • 6
Bohemian
  • 1,956
  • 2
  • 17
  • 24
  • In the last case, `final` does provide the partial guarantee that you're dealing with the same `Date` instance. Some guarantees are better than nothing (if anything, you're arguing for immutable classes from the ground up!). In any case, in practice much of what you say should affect existing immutable-by-default languages but it doesn't, which means it's a non-issue. – Andres F. Aug 26 '16 at 02:29
  • +1 for pointing to the risk "that code further down may use input". Still, I'd prefer my parameters to be `final`, with a possibility to make them non-final for cases like above. It's just not worth spamming the signature with a keyword. – maaartinus Aug 26 '16 at 04:50
  • 2
    I find the point that one may mistakenly use `input` instead of `lowercaseInput` moot. While technically correct, it's an easy to spot mistake once it causes you a bug, as you can clearly see the different semantics of the 2 separately named variables at their point of usage (provided you give them good names). To me, it's more dangerous to conflate 2 semantically different usages of separate values into the same variable and therefore the same name. It can make tracking down bugs more difficult, as you'll have to read and understand all preceding code that's somehow related to the 1 variable. – blubberdiblub Oct 23 '19 at 15:05
  • This is where a functional decorator would win the day. withLowerCased(input, input -> {...method body }); public T withLowerCased(String input, Function) { return f.apply(input.toLowerCase()); }. Now we can honor immutability, not add an exception path (which in my opinion breaks SOLID), and avoid local reassignment. – PlexQ Jul 05 '20 at 16:46
  • Why would you ever want a unit test to uncover an issue that could be prevented by the compiler? – Samurai Soul Jul 19 '23 at 17:37
8

I let eclipse put final before each local variable, since I consider it to make the program easier to read. I don't make it with parameters, since I want to keep the parameter list as short as possible, ideally it should fit in one line.

maaartinus
  • 2,633
  • 1
  • 21
  • 29
  • 2
    Also, for parameters, you can have the compiler issue a warning or error if a parameter is assigned. – oberlies May 29 '13 at 13:03
  • 5
    Quite the opposite, I find it harder to read as it just clutters up the code. – Steve Kuo Nov 02 '13 at 15:32
  • 3
    @Steve Kuo: It just allows me to quickly find all variables. no big gain, but together with preventing accidental assignments it's worth the 6 chars. I'd be much more happy if there was something like `var` for marking non-final variables. YMMV. – maaartinus Nov 12 '13 at 11:26
  • 1
    @maaartinus Agreed about `var`! Unfortunately it's not the default in Java and now it's too late to change the language. Therefore, I'm willing to put up with the minor inconvenience of writing `final` :) – Andres F. Aug 26 '16 at 02:24
  • 2
    @maaartinus Agreed. I find that about 80-90% of my (local) variables don't need to be modified after initialization. Hence, 80-90% of them have the `final` keyword prepended, whereas only 10-20% would need a `var`... – JimmyB Oct 24 '16 at 11:54