Monday, April 6, 2009

Don't let Java final Strings trick you...

Imagine working on some production issue, where a UI message has to be changed (for it not being as per specifications ofcourse). So, here you are, faced with a very simple 'defect' (if you term it one ;) ).

All that needs to be done is to change the value of a final String variable somewhere in your Interface or concrete class that contains the same (example below), followed by shipping out the class file as a patch. A 2 mins job - and actually, does not even need a 'programmer' to make the change. So, you happily make the change, ship the file (without even bothering to test - due to sheer confidence or may be over-confidence as we find out why further...)




    public interface ConstStrings{

      String CONST_1 = "Java";
      String CONST_2 = "Blogger";

      Integer i1 = 9;
      Integer i2 = 20;

    }




What happens when it reaches QA? Or worst still, the client? Boom, they still end up seeing the old incorrect message. What went wrong? Certainly, the message is changed in the class file and the patch is applied as expected!

Well, the problem turns out that, the UI class(example below) which refers to this class for getting the final constant variable has not been compiled! Now, try re-compiling the class that refers to the constant, and everything works as expected.


    public class ClassUsingConstants {
    private String str;
    private String str2;
    private Integer i1;
    private Integer i2;

    ClassUsingConstants() { // Constructor

      str = ConstStrings.CONST_1;
      str2 = ConstStrings.CONST_2;
      i1 = ConstStrings.i1;
      i2 = ConstStrings.i2;

    }

    // Getters for the variables are here...

    }


Behind the scenes, whenever you compile a class that refers to a String Constant (in another class or interface), the compiler creates the .class file with the constants embedded in it, instead of having a reference to the actual class that contains it. Hence, changing and re-compiling the referred class only is not sufficient, but what is actually required is re-compilation of all the classes that refer to the same.
However, a point to note here is that, this behaviour is exhibited only for Constant 'final' Strings and not for any other type of 'final' objects.



Hope this helps you, if it does, leave a comment :)

Friday, April 3, 2009

Beware - It could be the Java integer pool!

Most of the java-developers are aware of the String pool* that Java provides. However, not many are aware of the Integer pool that java provides - which is what I have observed from my interviewing over the last 1.5 years of candiates carrying experiences ranging from 1-3 years.

Integer pool is maintained by the JVM for Integers ranging from -128 to +127. So, when a line of code like:

    Integer i1 = 10;

is executed, the JVM checks for the same in the pool of Integers it maintains and pulls one from the same. Execution of such statements (or assignments) can be done safely without having to bother (which most of us don't anyway) about any side-effects. However, the problem surfaces when you execute the following lines of code...


    Integer i1 = 100;
    Integer i2 = 100;
    if(i1 == i2) {

      System.out.println("Wow Integer pool exists !!");

    }


The above code, when executed results in printing out the assertion that the Integer pool does indeed exist.
I leave upto you, to check what happens when the the values for i1, i2 are changed to 129.

And now a catch about it (for a good number of freshers out there :) ), the above code when changed to the following, results in nothing getting printed.


    Integer i1 = new Integer(100); // New Integer object is created and the pool is not queried.
    Integer i2 = new Integer(100); // ---- Same as Above ----
    if(i1 == i2) {

      System.out.println("Wow Integer pool exists !!");

    }


When the code above is executed, since we explicitly ask for a 'new' object, JVM does not bother to save memory for us :) and instead, gives us new objects.

Hope this is useful...