final parameters

G

gaijinco

I used C++ for quite a while and for a year or so I´ve been using
Java.

One of the most important things that rarely was used in C++ was to
make sure that, if applicable, all the parameters were declared const.
Even if rarely used, almost every book out there says it's good
practice.

Now for Java I have never ever read or heard someone saying that, if
applicable, the parameters should be declared final.

Why is that? Is there a backlash in Java doing so? Or you should
really make all appropiate parameters final?

Thanks.
 
G

gaijinco

I of course mean parameters in a function, like for example:

public class Foo
{
// Atributes
private int x;

// Constructor
public Foo(final int x)
{
this.x = x;
}

// Setters
private void setX(final int x)
{
this.x = x;
}
}
 
D

Daniel Pitts

I used C++ for quite a while and for a year or so I´ve been using
Java.

One of the most important things that rarely was used in C++ was to
make sure that, if applicable, all the parameters were declared const.
Even if rarely used, almost every book out there says it's good
practice.

Now for Java I have never ever read or heard someone saying that, if
applicable, the parameters should be declared final.

Why is that? Is there a backlash in Java doing so? Or you should
really make all appropiate parameters final?

Thanks.

The problem is that the meaning of "const" in C is very different from
the meaning of "final" in Java.

const implies (and somewhat enforces) that the value of the passed
argument will not be modified by the method...

final on the other hand only says that the reference to that argument
won't be changed.


public class FinalTest {
public String value;

public static void main(String...args) {
FinalTest ft = new FinalTest()
ft.value = "Hello";
System.out.println("before: "+ft.value);
finalParam(ft);
System.out.println("after: "+ft.value);
}
public static void finalParam(final FinalTest test) {
test.value = "World!";
/* test = new FinalTest(); // compile Error */
}
}


This difference is primarily from the fact that java passes everything
by primative value or object reference, never by object value, and
that java has no way to specify that an object reference should be
considered immutable (which is what const really means in c++)
 
A

Alexey

The problem is that the meaning of "const" in C is very different from
the meaning of "final" in Java.

const implies (and somewhat enforces) that the value of the passed
argument will not be modified by the method...

final on the other hand only says that the reference to that argument
won't be changed.

public class FinalTest {
public String value;

public static void main(String...args) {
FinalTest ft = new FinalTest()
ft.value = "Hello";
System.out.println("before: "+ft.value);
finalParam(ft);
System.out.println("after: "+ft.value);
}
public static void finalParam(final FinalTest test) {
test.value = "World!";
/* test = new FinalTest(); // compile Error */
}

}

This difference is primarily from the fact that java passes everything
by primative value or object reference, never by object value, and
that java has no way to specify that an object reference should be
considered immutable (which is what const really means in c++)

That's right, but I believe the OP was talking about the performance
benefits one might draw in C++ from "const" parameter declarations. I
actually recall reading something to that effect (declaring everything
that can be "final") with regard to Java back in the 1.0 days. And to
this day I find old code of mine littered with "final" parameters. If
I'm not mistaken the idea behind this is to help the compiler along
with various optimizations (stack vs heap memory?). As you've rightly
pointed out, many such optimizations are simply impossible in Java
because all non-primitive objects are passed by "pointer" only. So in
fact, final only applies to the value of the pointer, not the object
it's pointing to and it's very tough for the compiler to ascertain
that a particular object exhibits immutable behavior.

Interestingly, there are situations where the language _requires_ use
of finals and that's with anonymous inner classes accessing values
from their invocation context:

public void test(final int val1, int val2)
{
final int val3 = 0;
int val4 = 0;
EventQueue.invokeLater(new Runnable()
{
public void run()
{
System.out.println(val1); // legal
System.out.println(val2); // won't compile
System.out.println(val3); // legal
System.out.println(val4); // won't compile
}
});
}
 
R

Roedy Green

Why is that? Is there a backlash in Java doing so? Or you should
really make all appropiate parameters final?

The problem is making parms final exposes a detail to the outside
world that is none of their bloody business. It is a matter purely of
implementation within the method. I find that offensive though I am
usually a huge fan of final.

It is not as though Java CAN EVER change the values of the caller's
variables (other than changing their fields).
 
S

Stefan Ram

Roedy Green said:
The problem is making parms final exposes a detail to the outside
world that is none of their (...) business.

The finalness is not part of the interface.

interface I { void f( int x ); }

class C implements I { public void f( final int x ){ return 0; }}

The above should compile, and you are free to remove or
introduce the »final« anytime without breaking any interfaces
or clients.
 
S

Stefan Ram

Supersedes: <[email protected]>

Roedy Green said:
The problem is making parms final exposes a detail to the outside
world that is none of their (...) business.

The finalness is not part of the interface.

interface I { void f( int x ); }

class C implements I { public void f( final int x ){} }

The above should compile, and you are free to remove or
introduce the »final« anytime without breaking any interfaces
or clients.

Supersedes: <[email protected]>
 
G

gaijinco

But in the end if I have a method which receive a parameter that
doesn't have to change it would still be a good idea to make it final,
doesn't it?

For example in a constructor, obviously you will never want that a
parameter in a constructor to lose its value, at least before making
the correponding assigment with the appropiate atribute.

So even if it doesn't accomplish the same sort of optimization, it
just make sense, doesn't it?

class Foo()
{
int x;

public Foo(final int x) {
//
}

}


class Foo()
{
int x;

public Foo(int x) {
//
}

}
 
B

Ben Phillips

gaijinco said:
For example in a constructor, obviously you will never want that a
parameter in a constructor to lose its value, at least before making
the correponding assigment with the appropiate atribute.

The parameter cannot "lose its value".

A parameter in a constructor (or method, static or otherwise) is really
a local variable in disguise, one that gets preassigned with the result
of evaluating some expression where the method or constructor got called.

What happens if I execute


Foobar f = new Foobar(someList)

private List myList;
public Foobar (List theList) {
myList = theList;
}

is more or less as follows.

A reference "f" is allocated on the stack.
The expression "someList" is evaluated, presumably to a List reference
(under the hood this is most probably a machine pointer).
Memory for a new Foobar is allocated (here is where any OOME is thrown),
including for a reference "myList".
A reference "theList" is allocated on the stack.
The pointer to the list referenced by "someList" is copied to "theList".
The code being run jumps into the Foobar constructor's code.
The pointer at "theList" is copied to "myList".
At some time during all of this, the "f" reference is made to point to
the new Foobar object being constructed.

This is what happens conceptually; there may well be optimizations in
practise, especially with JIT compiling.

In any event, if "someList" is reassigned before the constructor is
called, the newer value is what gets copied to "theList"; otherwise the
older value is copied. (With concurrency, a race condition may make it a
toss-up which version gets copied.)

But "theList" gets one version or the other, and this version is copied
to "myList". If "someList" is changed to point to another List (or to
"null") after it was copied to "theList", "theList" still points to the
earlier List, and "myList" still ends up pointing to that List.

Maybe it's easier if an integer is used. A machine pointer and an
integer are probably the same thing at the bottom level, modulo the
hardware you use, anyway, but some things should be clearer.

So "someInteger" is equal to, say, 5. When the constructor is called,
"theInteger" gets set equal to 5. If "someInteger" is changed to 6 by
some concurrent code, "theInteger" remains equal to 5, because it's a
different integer; it's a copy. Eventually "myInteger" ends up being 5
(not 6).

The tricky case is when the object is mutable. So "someList" points to a
list, "theList" gets pointed to the same list, and someone adds
something to the list, then "myList" gets pointed to the list. Since
there's only the one list, the change is visible everywhere, but it
wouldn't have mattered. If the change happened before "theList" was
assigned, "myList" still ends up pointing to this list, and still it has
the extra item. If "myList" points to the list before the change is made
to the list, "myList" stays pointing to the same list, but someone
iterating over the list a couple of times with "for (Foo x : myList)"
may see a new item the second time they do so. This isn't peculiar to
constructors, and it wouldn't be prevented by making "theList" final, or
even by making "myList" final. This doesn't stop the list being
modified; it only stops the named reference being pointed at some other
list later, or becoming null.

Even using "Collections.unmodifiableList" somewhere along the way won't
stop someone changing the list that has a reference to the original list
object and not just the wrapper returned by the aforementioned method,
or make the list change invisible to "myList" users.

To make the list never get modified of course it can be wrapped in
"unmodifiableList" as soon as it's built and populated appropriately,
and all direct references to the original, mutable list discarded.

To make the Foobar constructor not see any modifications means passing
it a copy of the list: "Foobar f = new Foobar(new ArrayList(someList));"

To make the Foobar object unable to ever see any modifications the
constructor itself can copy the list: "myList = new ArrayList(theList);"

Even then the Foobar might have methods "return myList;" and then see
changes made to the list; "return Collections.unmodifiableList(myList);"
prevents that, and a single unmodifiable view can be constructed and
stored in an ivar to return instead of making a new one each time of
course. Either way the Foobar has a private copy of the list and doesn't
let anyone else ever get hold of a reference to it that can be used to
change it.

And even then, if the list contains objects that are themselves
modifiable, such as more lists, or sets or maps or whatever, one of
these might be altered and the change visible through the Foobar
instance's "myList" ivar.

Needless to say, it is often best to use unmodifiable object types,
including Collections.unmodifiableFoo, liberally, and encapsulate all
mutable state. Making ivars "final" helps make and enforce unmodifiable
object types.

Making constructor (or other) parameters "final" doesn't do anything of
the sort.
 
E

Eric Sosman

gaijinco said:
But in the end if I have a method which receive a parameter that
doesn't have to change it would still be a good idea to make it final,
doesn't it?

It doesn't make much difference. Personally, I declare
parameters as final if

1) The consequences of changing them would be bad (which
is seldom a concern in a pass-by-value language), or

2) They will be used by inner classes created within the
method (in which case Java *requires* them to be final).

Absent one or the other of these, I don't use final parameters:
they're just visual clutter, something that Java doesn't lack.
For example in a constructor, obviously you will never want that a
parameter in a constructor to lose its value, at least before making
the correponding assigment with the appropiate atribute.

If the constructor is doing so many things that it could
get confused, the constructor is probably doing too much. Again,
opinions vary. Most of my constructors consist of a little bit
of validation and then a few assignments to instance variables,
not enough code to offer a reading comprehension challenge.
So even if it doesn't accomplish the same sort of optimization, it
just make sense, doesn't it?

I don't feel that way. A parameter without `final' is like
a fish without a bicycle.
 
C

Chris Dollin

gaijinco said:
But in the end if I have a method which receive a parameter that
doesn't have to change it would still be a good idea to make it final,
doesn't it?
Why?

For example in a constructor, obviously you will never want that a
parameter in a constructor to lose its value, at least before making
the correponding assigment with the appropiate atribute.

If the constructor is so big that you can't /see/ that the parameter
is erroneously assigned, it's too big anyway. (And won't your unit
tests fail if you mess up the assignments?)
 
R

Roedy Green

The expression "someList" is evaluated, presumably to a List reference
(under the hood this is most probably a machine pointer).

The Java Byte Code interpreter model pushes evaluated parameters to
the stack when you make a call. When the callee wakes up the
parameters are sitting there on the stack looking for all the world
like local variable slots on the stack. That way the callee can treat
parameters and locals almost identically.

Primitive values are pushed directly to the stack. References are
pushed as a 32- bit (or 64-bit) pointer.

Read the Goldfish bowl book. See http://mindprod.com/jgloss/jvm.html
The JVM spec gives immense latitude how it is ACTUALLY implemented so
long as it behaves logically like the model.
 
R

Roedy Green

The finalness is not part of the interface.

That is reassuring. I did not in the least like the idea I would
force clients to recompile as I tweaked the finalness of parameters.

I don't think the finalness should be exposed in generated Javadoc
either. I have not experimented to see if it is.
 
T

Thomas Hawtin

Roedy said:
I don't think the finalness should be exposed in generated Javadoc
either. I have not experimented to see if it is.

On parameters, no it isn't. At least not in any sensible version. Really
early implementations did, but you shouldn't see them anymore. final is
displayed when applied to fields, methods and classes.

Tom hawtin
 
R

Roedy Green

On parameters, no it isn't. At least not in any sensible version. Really
early implementations did, but you shouldn't see them anymore. final is
displayed when applied to fields, methods and classes.
Good to hear. That is how it should be.
 
O

Oliver Wong

gaijinco said:
But in the end if I have a method which receive a parameter that
doesn't have to change it would still be a good idea to make it final,
doesn't it? [...]

So even if it doesn't accomplish the same sort of optimization, it
just make sense, doesn't it?

As most poster have told you, it doesn't really make much pragmatic
difference either way.

However, it seems most of these posters therefore conclude "don't
bother making your params final". I'm of the opposite opinion: Since it
doesn't matter either way, make them final by default. I like having as
many of my variables final as possible.

- Oliver
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top