Fog Creek Software
Discussion Board




const vs Java final

I'm fully aware that C++ const isn't quite the same as Java's final, but I'm an anal-retentive Java programmer, and the 'const' thread caught my attention.

In Java, I can flag my method parameters (or any local variables) as 'final', indicating to the compiler that their value should not change in the scope of the method.  This doesn't affect the interface at all, and doesn't affect what methods I can pass my parameters to, but makes the compiler more aware of my intentions, and allows the compiler/vm to make various optimizations.

Still, I don't see very much (if any) Java code written like this - typically the only time you see final used like this is when working with inner classes that require some variables to be declared final.  Is it because of the differences between 'final' and 'const' that java programmers think 'final' doesn't matter?  Is it because it only forces the reference to be unmodified and not the underlying object, and therefore is too weak?  Or are java programmers just generally not anal-retentive enough?

schmoe
Tuesday, March 16, 2004

I've heard many Java developers say that 'using final everywhere' obfuscates the code.  I would assume they view this cost as not worth the benefit.

Scot Doyle
Tuesday, March 16, 2004

"Or are java programmers just generally not anal-retentive enough?"

Read: worse programmers

_
Tuesday, March 16, 2004

"final" is sufficiently different from "const" to make the considerations completely different.  In C++ you can declare parameters that are passed by reference to be const, so the caller knows it isn't changed.  In Java you can only pass variables by value, and so it has no meaning to the caller if a  parameter is final or not, since it can never be changed.  Note, that I am saying the variable can't change.  If the variable is a reference (Object), then the object it refers to can be changed and there is NO WAY in Java to prevent this.

Ignoring inner classes, there really isn't a good reason in Java to declare a local variable final (and method parameters can be considered local variables), because their scope is only in this method, and if your methods aren't too big or complex (they aren't are they?), then it is fairly easy to tell if you are changing it or not. 

madking
Tuesday, March 16, 2004

I'm one of those people who declares method parameters and local variables to be final only when explicitly required.

Why? Because it doesn't really buy you much. It doesn't optimize anything, since modern compilers can easily determine if a parameter is changed within a method.

All it does is prevent you from assigning the parameter to some other value. If the object is mutable, you can still alter the object's state. For example:

// will not compile
void someMethod(final List foo)
{
    foo = new ArrayList();
}

// ok
void someMethod(final List foo)
{
    foo.add("bar");
}

One case final can be useful is if you have a local variable that should only be assigned once. For example, perhaps you have a switch or if-else-if ladder that should only ever result in the value being assigned once. This can be useful for catching silly errors. For example, the following will not compile because the variable foo is assigned twice if the variable bar == 2:

final int foo;

switch(bar)
{
    case 1:
        foo = 10;
        break;
    case 2:
        foo = 20;
        // oops, we forgot the "break"
    default:
        foo = 30;
}

Burninator
Tuesday, March 16, 2004

As mentioned earlier, const and final are two *very* different creatures.  Just look at the benefits (and complexity) you get from marking methods as const.  There is no java equivalent.

As far as optimization goes, final makes very little difference,  I only use it for constant values:  i.e.

final public String MAGIC_VALUE = "com.example.locationInSession";

beyond that you get very little from it.

Koz
Tuesday, March 16, 2004

Totally understand and agree that final isn't as useful/loaded as const.  But isn't it a compiler-understood way to make explicit (some of) my intentions about a parameter/variable?  Isn't that nearly always a good thing?  What's the difference between the reasonable java programmer saying "final obfuscates the code" and the l33t hacker saying "variable names longer than 2 characters are unnecessarily verbose"?

I agree with what's been said here so far, and my personal practice is to only use final parameters & local variables when necessary, but it doesn't feel entirely consistent to me.

schmoe
Tuesday, March 16, 2004

Schmoe, a psychological difference is that with final parameters, you code mainly for the compiler, and incidentally for humans.  It is the other way around with readable variable names.

In Java, specifying things to the Nth degree seems logical.  Perhaps this is because Java is unusually verbose, and that verbosity presents a number of decision points for a coder to guard against.

But it's really up to you; you're 10X better than the type who doesn't care about their code.  _Hardcore Java_ by O'Reilly cites this technique, and that chapter is online.  So when someone inevitably brings it up, you can score massive hardc0re cred.

Tayssir John Gabbour
Tuesday, March 16, 2004

I think the biggest point is that declaring the parameter final in the method makes absolutely no difference to the client of the method. And inside the method, you can usually figure it out yourself. The only time you need to need to make a variable final is when you want to reuse it inside the method body by an inner class or another thread.

On the other hand, I think people don't use final methods and volatile enough.

genius
Tuesday, March 16, 2004

> allows the compiler/vm to make various optimizations

I would be very surprised if anyone could measure any speed gain from declaring any variable final.
Anyway, aside from loops and counters, I don't find myself assigning to variables more than once.  What if final were default?  (Aside from breaking every piece of code ever written).

> I think people don't use final methods and volatile enough

True.  Final methods would be more useful if subclasses could override private methods.  What's that pattern called?  The Template Pattern?  I don't have my GOF book here.  It works better in C++, but the way to do it in Java is with a public final method.

Volatile I'm not so sure about.  Just synchronize, otherwise there are no guarantees, especially on multiple CPU machines.  Check-lock-check is fundamentally unsound.

Brian
Tuesday, March 16, 2004

The sample chapter of Hardcore Java talks about why you should use final: http://www.oreilly.com/catalog/hardcorejv/index.html (and click on sample chapter - The Final Story).

I'm not really sure why all method parameters aren't final by default really. It seems pretty dangerous to allow a method to reassign a reference. If I pass x into method foo, I generally don't want foo to change what x refers to.

Walter Rumsby
Tuesday, March 16, 2004

I use final on classes that I provide to people that I deliberately don't want them to derive from.

i like i
Wednesday, March 17, 2004

>If I pass x into method foo, I generally don't want foo to change what x refers to. <

I'm afraid you don't understand how pass-by-reference works in java. The method gets its own reference called x that has nothing to do with your reference called x except that it references the same object.  If inside the method, x is assigned to another object, that has no effect on the caller's reference.

On the other hand, there's simply no way of preventing the method from modifying the object (as with const) a la x.setFoo(newValue), unless the object is immutable. That is the biggest difference between const and final.

So, the final modifyer on a method parameter is only useful within the method implementation itself; it's of no use to the invoker. For instance, if inside the method you wanted to create an anonymous inner class and reference x from inside it, x would have to be declared final.

Hope this helps.

genius
Wednesday, March 17, 2004

Hmm,

public class URLTest {
    public static void main( String[] args ) {
        try {
            URLTest test = new URLTest();
            test.bar();     
        } catch ( MalformedURLException e ) {
            System.err.println( e.getMessage() );
        }
    }
   
   
    public URLTest() {
       
    }
   
   
    public void bar() throws MalformedURLException {
        URL u = new URL( "http://www.google.com" );
        this.foo( u );
       
        String p = u.toString();
       
        System.out.println( p );   
    }
   
   
    public void foo( URL u ) throws MalformedURLException {
        u = new URL( "http://www.yahoo.com" );
    }
}

Right you are (program outputs "http://www.google.com").

Walter Rumsby
Wednesday, March 17, 2004

*  Recent Topics

*  Fog Creek Home