Java Final Arguments

In some Java source the convention of declaring an argument final has started to appear. This declares that the variable passed in cannot be reassigned, and the compiler will complain. Changing the above example to say void foo( final String bar ) causes my javac to complain with

 : variable bar might already have been assigned to
    bar = "foo";

This construction and some of it's similarity and differences from the C++ const declaration are clear, but what JavaSubtleties are waiting to surprise us?

--StevenNewton


I only declare parameters or method scoped variables final when i need to access them from anonymous inner classes (which is occasional; i only tend to use them for allocate/release mechanisms).

Otherwise, I find it to be an irritating extra bit of syntactic noise (which Java already has a lot of), which the pass by reference semantics of the language make largely redundant anyway.

Also, explaining that final does not make objects immutable to new Java programmers gets tiresome after a while.

--ShaunSmith


It's not a convention (if it is used as convention, it reflects a misconception). Using formal parameters as local variables (assigning to them) is merely a convenience in Java, unlike in C++ where assigning to a reference parameter will have effects outside the current scope to the variable that was aliased by the parameter. But in Java "final" is mandated if you want to have instances of inner classes declared within the method scope reference the formal parameter of the method. Example:

 UnaryOperator? bind ( final BinaryOperator binOp, final Object boundLeftArg) {
    return new UnaryOperator?() {
         public Object apply(Object arg) {
                return binOp.apply(boundleftArg, arg);
         }
    };
 }

As it shows it's ridiculously verbose --compared with similar construction in other languages, and it has no subtlety other than it forces you to declare parameters as final.

final is misleading because it means different things for methods and different things for variables and methods. For methods it means cannot be overridden. For variables it means "it can only be initialized but not assigned to". Especially since a variable declared "final" is not generally expected to have the behaviour of a constant, final looks quite funny cause it promises essentially nothing.

In this example, the caller should not assume (inspite the final keyword) that the object passed as boundLeftArg, will not be modified because it is declared final. Final in this context has no significant semantic other than allowing for the inner class construction. --CostinCozianu


Of course these arguments about final and objects apply to C++ and const as well. There's nothing to prevent a method that takes a const object from calling methods that change that object's state, but it does prevent reassignment of the variable.

  someMethod(const *anObject) {
      anObject->mutatorMethod();
  }

is fine but

  someMethod(const *anObject) {
      anObject = otherObject;
  }

is not.

This is similar to the effect of final in Java. The inner class usage is true, but not relevant in this case. Of course in neither C++ nor Java does it make the object immutable, but that's a different issue.

Are you absolutely sure ? Since the last time I programmed in C++, I recall that the compiler shouldn't allow calling non-const methods on const objects (static variables, pointers or references). In the example above what we miss is the type specification, so that we can know whether the const modifies the "pointer type" or the actual type. But the compiler should give you an error unless mutatorMethod is declared const. In which case the compiler makes sure that mutatorMethod is not a mutator. I'd argue C++ const is essentially different, and is what Java should also have (at least in theory).

const might make sense, but in C++ const-correctness is quagmire of no small consequence. My on C++ is rusty enough that I don't know if I meant Type* const anObject or Type const *anObject. The fact that it matters is the subject for an entire essay on its own.

I think the above example is meant to be

  someMethod(Type* const anObject)
(or is it someMethod(Type const *anObject)? The placement of the const keyword in C++ has its own subtleties). In that case, the pointer cannot be assigned, but non-const methods can be invoked, which is identical to Java's final.

Or even...

  void someMethod( const Type& object );
But you can also say:

  someMethod(const Type * const pObject)

Which is what you wish for. No assignment, no mutator. But please note that in case of

  someMethod(const Type *pObject) {
   ...
   pObject= NULL; //or whatever else
   ... 
 }

has no side effect on the caller because the pointer itself was passed by value. Which is also why Java's final for arguments is really useless. It could just as well have stated that instances of the inner classes bound to method scope have access to the values that are passed in by the callee.

A better deed in C++ would be to use

 someMethod(const Type * const * pObject) 

in which case it kind of make sense because if it wasn't for the second const an assignment to (*pObject) would sideffect the caller. The second const prevents assignment to (*pObject) or to pObject[i]. Nice isn't it?


If you want to have const objects in Java, you could create an immutable interface that offers no set methods:

  public interface ConstInt {
    int getValue();
  }

public class Int implements ConstInt { private int value; public Int(int value) { this.value = value; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } }

and then

  ConstInt random = new Int(17);
  doSomething(random);

Unfortunately, anyone can just cast random back to Int. And, this isn't XP-ish. I gues const is not part of the Java idiom.

--EricJablow

No, it isn't for no good reason other than they're busy adding lots of other quite unnecessary features. Am I crazy to declare const Interfaces ? No, I'm not.

I can even make them cast safe, by simply delegating to the object, instead of offering the const interface directly thriough the object, so no ugly villain can subvert my code.

Since Java 1.3, with a bit of gymnastics, I can have a ConstFactory?:

/**

 * Gets a declared "const" interface (i.e. a collection of methods that the programmer thinks 
 * are non-mutators aka C++ const methods), and the object to which those methods applies
 * and returns a guaranteed const object implementing strictly the passed in const interface.
 */
public class ConstFactory? {
  public static Object makeConst(Class ConstInterface?, Object targetObject) {
   // guess what's coming here
  }
}

But:

One of the worst plagues of Java is that you have to write way too many lines of code, to express extremely simple ideas. In this case to express an one word idea, I'd have to add lots of lines of code, plus creating one more compilation entity. Don't even start me on what gymnastics I have to do to use functional composition techniques in Java :) --Costin

Are you using proxy classes? Also, look at the Colt library for functional code. --EricJablow


For immutability, I tend to use what I call a model; but I have also seen it documented as the EssencePattern? in PLoP3. --ShaunSmith

Do you mean the EssenceObject?


EditText of this page (last edited November 13, 2014) or FindPage with title or text search