views:

1930

answers:

9

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.

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

B) 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;  
}
+14  A: 

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

Jon Skeet
Well... what have the Romans ever done for us?
matt b
Sanitation, medicine, education, wine, public order, irrigation, roads, the fresh water system and public health. Oh, and peace =8-)
Yuval
But to paraphrase Krusty with his danish, what have they done for us *LATELY*? =)
James Schek
+1  A: 

I am suggesting that there might be a significant body of developers who misunderstand "final" to have more effect than it really has.

I think that for some developers, "final" as a method parameter, unlike as a local field modifier is a misleading concept.

Adding final to parameters is so good an idea that Eclipse has a Source Cleanup option for it. It declares that the object in the variableis the same all through the method, which is important for maintainers who need to understand it fast.
Thorbjørn Ravn Andersen
You think there are lots of programmers who believe that final parameters behave differently to final local variables? I find that hard to believe. Do you have any evidence of this?
Jon Skeet
parameter = var; instead of var = parameter; no misunderstanding of what it does, added safety is a good thing.
TofuBeer
+5  A: 

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.

Germán
A: 

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.

starblue
+7  A: 

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.

Michael Borgwardt
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
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.
Michael Borgwardt
It doesn't make a copy, it is simply a reference to whatever object was referenced.
vickirk
@vickirk: sure it makes a copy - of the reference, in case of reference types.
Michael Borgwardt
A: 

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 test on a method declaration isn't an issue.

Fortyrunner
+3  A: 

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

jsha
A: 

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.

Michael Rutherfurd
A: 

Using final on method parameters in an optimization. Parameters are passed by reference. But what happens if I modify a variable that was passed by reference as a parameter? It won't break, because Java has made a copy for the function to use as it wishes. What about the overhead for this copy? That's where "final" comes in. If you specify "final" you can't modify teh parameter in the function (the "compile-time" checking will prevent it). Thus, the compiler does not nee dto make a extra copy of teh variable in case it is messed with, since it won't be. So you get the savings of not making an extra copy if you are not going to modify it anyway. Why not always have final by default? What if you want to use teh parametr as a variable to mess with? By not having it assumed final, you save a line of code that would declare a copy of the variable. I could see a case being made for this, but it doesn't seem like a big deal either way.

-Dan8080

"My IQ is bigger than my shoe size, and I have BIG feet" -anonymous

Dan8080