Skip to main content
  1. Posts/

The ‘final’ Frontier in Java

·763 words·4 mins
Java Programming

Introduction #

Although this post came about primarily to help my son learn Java, it still amazes me how many professional developers do not understand this basic premise in Java (Programming Language) even after working with it for Years. I am yet to find any Java book that opens with Big Chapter on this very critical topic, instead they mention it in a few hardly intelligible sentences. Meanwhile Java continues to gain momentum as most popular language, primarily because of how easy it seems to use! Let me be the first to tell you that Yes, it is Easy, provided you fully grasp the concepts outlined below.

Quick primer before diving into Java – most operating systems organize memory for a running program as Heap and Stack. These are just designations for areas of memory allocated to your program, but the way they are utilized differs slightly as we’ll see below. And if you don’t know what Object is, for our purposes it’s just a little set of data organized together.


Pointers #

There is fundamental difference in Java between Object variables and Primitive variables. The latter is those built-in types we all grew to love from most languages, like int, long and float. They are actually very high performance as well because they are quickly allocated on the Stack and CPU operates on them via Native commands.

Meanwhile Objects in Java are just Pointers! Let me demonstrate with this simple example:

public static void main(String[] args) 
    int a = 1;
    int b = a;
    System.out.println("A: "+a+" B: "+b);
    ArrayList aLst = new ArrayList();
    ArrayList bLst = aLst;      
    aLst.add("I Live in List");
    System.out.println(" A List Size: "+aLst.size()+
                       " B List Size: "+bLst.size());

Although lines 3-5 look conceptually similar to lines 9-12, the output is very different:

A: 3 B: 1
A List Size: 1 B List Size: 1

With Primitives we see that assigning a into b truly made a copy, so that when we put 3 into a later, nothing happened to b. Meanwhile, assigning aLst into bLst seems to act differently, as modifying aLst makes something magically appear in bLst!


Objects #

Although our most respected Java Designer Mr. Gosling tried to hide the pointers complexity away from average developer, it still shows through sometimes, especially when calling Methods and passing Objects around:

public static void callMeMaybe(ArrayList third, int howOften) 
  howOften = 1;
  third.add("+1 800-555-1212");

public static void main(String[] args) 
  int a = 800;
  ArrayList first = new ArrayList();
  ArrayList second = first;
  first.add("Unlisted Number");

  callMeMaybe(second, a);

  System.out.println("Our List: "+first);
  System.out.println("A: " + a);

And here is the output, hopefully what you expected by now:

Our List: [+1 800-555-1212]
A: 800
What Is Happening?>

What Is Happening? #

What has happened to our Unlisted Number? And if the evil callMeMaybe method was able to eliminate it, why did we not extract the essential howOften to call information from that same method?

The basic way to understand the difference is to simply remember the Primitives versus Objects distinction. The more complete explanation is that Objects live in the Heap, while pointers to objects (such as first, second and third in our example) live along with Primitives, in the Stack. Each time our program enters a method, new variables (sometimes with copies of values from existing variables) get created on the Stack, and once method is finished, they are released. But even though once callMeMaybe method finishes our third variable gone into the great beyond (along with howOften variable), the object it was pointing to lives on in the Heap, and still available for first to see.


Finally #

Having understood this we are finally ready to discuss Java’s ‘final’ keywordWinking smile

Simply put, when this keyword is placed on variable definition, you can only give this variable one value in it’s lifetime. A more complete explanation about the use of final keyword can be found on Wikipedia. My personal recommendation is that you avoid using this keyword, except when defining some truly Constant value in all upper case, like so:

public static final int REQUIRED_SLEEP_FOR_HEALTH = 8;

And especially avoid using it when declaring Object referencing variables, since it does Not do what you would expect. As a simple example, if we were to define third variable in example above as final, it would have no impact on our program behavior or output!

While there are few other cases where final should be used, remember that Optimization is Not one of them.

Good Luck!

Featured Art: by Karl Pawlowicz on Unsplash