The Java equivalent of const

The const keyword is a means of marking a variable as giving "read-only access" in C++. What is the equivalent of const in Java?

The Java equivalent of const depends on the type of variable— primitive or object— and on what you want to make constant— the object contents or the "pointer" (reference in Java). The situation can be roughly summed up as follows:

Nearest equivalents to the C++ const keyword in Java
Variable typeConstant object/variable contentsConstant pointer
Primitivefinal variablefinal array reference (see below)
ObjectUse an immutable object or create a subclass that forces object reference

The Java final keyword

First, the combinations that are relatively easy to immitate in Java. The Java final modifier marks a variable as unmodifiable once it has been set. If it is a primitive variable such as an int, then this makes the actual value unmodifiable; if it is an object reference, then the reference can't be changed, but the object itself can still be modified if it provides a means to do so:

final int x;
x = 7;   // OK : first time the var is set
x = 8;   // NOT OK : can't modify once set

final Rectangle r = new Rectangle(0, 0, 20, 20);
r.x = 10;               // OK: it's the reference
                        // that's final
r = new Rectangle(...); // NOT OK: can't
                        // change the reference

If the final variable is an instance variable (a variable that belongs to an instance of an object), then the contract is that it must have a value set (and only once!) by the time the constructor exits.

There's no real equivalent to the constant pointer to a primitive, since Java doesn't allow pointers to primitives in the first place. (Strictly speaking, object references aren't quite like pointers either, but we consider them functionally similar here.) The nearest equivalent in Java is to use a single-element primitive array. So the equivalent to this in C++:

int *val;
*val = 3;

would be to do this in Java:

int[] val = new int[1];
val[0] = 3;

Making the array reference final has essentially the same semantics as a const primitive pointer:

final int[] val = new int[1];
val[0] = 3;       // OK
val = new int[1]; // Not OK : can't change final reference

Array with unmodifiable contents?

Java doesn't provide the notion of a const array: that is, an array that can be swapped for a new array (in C++ terms, "the pointer can be modified"), but whose elements can't be changed. However, if you need this functionality, the solution is generally much like providing read-only access to any other object as discussed below. So a couple of possibilities are:

To create a read-only IntBuffer, we first create the buffer, fill it, then call asReadOnlyBuffer() to create a reference to an object that provides read-only access:

IntBuffer ib = IntBuffer.allocate(10);
IntBuffer constBuffer = ib.asReadOnlyBuffer();

Immutable objects

One feature of the C++ const keyword is that it allows the caller to force read-only access on an object that would otherwise be modifiable. Arguably, such a design makes a bit more sense in C++, which still provides structs that have no way to enforce an access policy on its members.

In Java, the general ideology is that access policy to the state of an object is controlled by the class. In other words, the general way to make a field "read-only" is to make it private and then not provide any public method to set it!

So what if we have an object type that is normally mutable, but we want to make an instance of it immutable "on this occasion"? Well, we're essentially forced to use or create a subclass of the object in question. In the subclass, any methods that would normally update the state of the object can be "disabled":

So for example, an equivalent of this:

myFunction(const list l) {
  // ...
  // compiler won't let us accidentally modify l

in Java would be:

myFunction(List l) {
  l = Collections.unmodifiableList(l);
  // ...
  // at runtime, we can't modify l

As noted in the comments, a difference is that an attempt to access the unmodifiable object will be caught at runtime rather than compile time (as is the case with the const keyword).

Making public fields immutable?

If a field on an object is declared public, there's really no way to prevent modification of that field. This means that there's no way to subclass and make immutable an object such as Rectangle, whose fields x, y, width and height are all public (with hindsight, probably bad design!). So if we have a method that uses such an object, we have a couple of options depending on why we wanted const in the first place:

If we want to prevent accidentally updating the object in question from our own method, then we could create our own accessor class that is a "read-only wrapper" around the object in question, then only ever use the accessor class. Usually, this is too long-winded to be worthwhile— it's a fairly heavy solution to spotting what's often a fairly rare bug. But the idea would be to implement something like this:

myFunction(const rectangle r) {
  // ...

as follows in Java:

class RectangleAccessor {
  private final Rectangle r;
  RectangleAccessor(Rectangle r) {
    this.r = r;
  public int getX() { return r.x; }
  public int getY() { return r.y; }
  public int getWidth() { return r.width; }
  public int getHeight() { return r.height; }
myFunction(Rectangle r) {
  RectangleAccessor ra = new RectangleAccessor(r);
  r = null; // so we can't accidentally modify
  // Now only access via 'ra'
  // ...

In reality, this isn't idiomatic Java. But you might occasionally want to do it if it really helps you spot a bug.

The other situation that can occur is when you aren't sure whether a particular library method will alter a given object that we pass in. In its C++ cousin, if the parameter in question had been declared const, we'd take this as a hint that it the function in question wouldn't modify it. In Java, one form of defensive action is usually to pass in a copy of the object in question if it's something trivial such as a Rectangle:

Rectangle r = ...
callMethodThatMayAlterR(new Rectangle(r));

(If the object doesn't provide an explicit constructor to make the copy, then many standard JDK objects are cloneable.)

You might think this is inefficient. And it is, just ever so slightly. But on a modern VM it's really not so bad either: the overhead is probably a few machine instructions more than passing by value in C/C++ (where in any case, the whole object would be copied on to the stack).

What to read next

You may be interested in the Java equivalents of other C/C++ functions and keywords, such as the Java equivalent of pointers or the Java equivalent of malloc.

If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.

Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.