Saturday, 14 October 2017

Immutable Java objects & Why String is immutable


Immutable objects are simply objects whose state (the object's data) cannot change after construction.
Examples of immutable objects from the JDK include String and all Wrapper classes like Integer, Double...

Make a class immutable by following these guidelines:

  • Make all fields final.
    • When you define fields as final in Java, you must either initialize them at declaration time or in the constructor. Don't panic if your IDE complains that you don't initialize them at the declaration site. It'll realize that you've come back to your senses when you write the appropriate code in the constructor.
  • Make the class final so that it cannot be overridden.
    • If the class can be overridden, its methods' behaviors can be overridden as well, so your safest bet is to disallow subclassing. Notice that this is the strategy used by Java's String class.
  • Do not provide a no-argument constructor.
    • If you have an immutable object, you must set whatever state it will contain in the constructor. If you have no state to set, why do you have an object? Static methods on a stateless class would work just as well. Thus, you should never have a no-argument constructor for an immutable class. If you're using a framework that requires this for some reason, see if you can satisfy it by providing a private no-argument constructor (which is visible via reflection).
  • Notice that the lack of a no-argument constructor violates the JavaBeans standard, which insists on a default constructor. But JavaBeans cannot be immutable anyway, because of the way the setXXX methods work.
  • Provide at least one constructor.
    • If you haven't provided a no-argument one, this is your last chance to add some state to the object!
  • Do not provide any mutating methods other than the constructor.
    • Not only must you avoid typical JavaBeans-inspired setXXX methods, but you must also be careful not to return mutable object references. The fact that the object reference is final doesn't mean that you can't change what it points to. Thus, you need to make sure you defensively copy any object references you return from getXXX methods.
  • If the class has any mutable object fields, then they must be defensively copied when they pass between the class and its caller

Following example implementation demonstrates how to create an "immutable class" 

“Classes should be immutable unless there's a very good reason to make them mutable....If a class cannot be made immutable, limit its mutability as much as possible.”

Benefits of immutability: 

They:

  • are simple to construct, test, and use
  • are automatically thread-safe and have no synchronization issues
  • don't need a copy constructor
  • don't need an implementation of clone
  • allow hashCode to use lazy initialization, and to cache its return value
  • don't need to be copied defensively when used as a field
  • make good Map keys and Set elements (these objects must not change state while in the collection)
  • have their class invariant established once upon construction, and it never needs to be checked again
  • always have "failure atomicity" (a term used by Joshua Bloch): if an immutable object throws an exception, it's never left in an undesirable or indeterminate state
“The impact of object creation is often overestimated and can be offset by some of the efficiency associated with immutable objects. These include decreased overhead due to garbage collection, and the elimination of code needed to protect mutable objects from corruption.”

Why is String immutable in Java?

An immutable object is an object whose state cannot be modified after it is created. This is in contrast to a mutable object, which can be modified after it is created. In some cases, an object is considered immutable even if some internally used attributes change but the object's state appears to be unchanging from an external point of view. Here, we look into the String immutability, why it is necessary, what's its use and what is string pool in Java.

Ways to create string:

There are two ways to create a String in java.
  • With new operator
  • Using string literal or constant
For example,

String Literal pool:

String allocation, like any other object creation proves costly in time and memory.The JVM do some trickery while instantiating the string literals to increase performance and decrease memory overhead. To decease the number of creation of String object in JVM, the String class keeps a pool of Strings. Each time you create a string literal, the JVM checks the string literal pool first. If a string is found in the pool, a reference to the pooled string is return.if the String is not exist in the pool, a new string object is instantiates, then placed in the pool.

String is immutable for several reasons, here is a summary:

  • Security: parameters are typically represented as String in network connections, database connection urls, usernames/passwords etc. If it were mutable, these parameters could be easily changed.
  • Synchronization and concurrency: making String immutable automatically makes them thread safe thereby solving the synchronization issues.
    • Since String is immutable it can be safely shared between multiple threads which is very important in multi threaded application and to avoid any synchronization issue. Also you no need to synchronize String operation externally.
  • Caching: when compiler optimizes your String objects, it sees that if two objects have same value (a="test", and b="test") and thus you need only one string object (for both a and b, these two will point to the same object).
    • String in immutable means, no one can change its contents once created and which guarantee the hashcode of string to be same in multiple invocation. So Java, cache the string hashcode and do not calculate every time we call its hashcode method of string, which make it very fast as hashmap key used in HashMap in java.
  • Class loading: String is used as arguments for class loading. If mutable, it could result in wrong class being loaded (because mutable objects change their state).
    • Had string been immutable, a request to load jdbc.driver could have been changed to "mysql.driver".
  • That being said, immutability of String only means you cannot change it using its public API. You can in fact bypass the normal API using reflection. See the answer here.
  • Imagine String pool facility without making string immutable.It is not possible at all because in case of string pool with one string object/literal
    e.g. "Java World" has reference by many reference variable, if one them change the value others will be automatically affected i.e. let say
    String A="Java World"
    String B="Java World"
    Now String B called "JAVA WORLD".toUpperCase() which change into JAVA WORLD, so A will also be changed which is not desirable .
This is the same reason for making String final.
Though final and immutable are 2 different things e.g. StringBuffer is a final class in java but still mutable. But certain feature of String class will not be possible until string is final.

equals()  vs  ==

equals() can be consider to perform a deep comparison of the value of a object. It compare the content of 2 objects rather then references. Whereas == perform a shallow comparison. == operator with reference type evaluate to true if the references are identical means point to the same location.
Example :

The creation of 2 string with the same sequence of letters without the use of new operator will create pointers to the same location in string literal pool. The literal pool is a way java conserves resources.

String.intern()

The Java String class has a method called intern(), used to create an internal pool of unique strings. Given a string str, saying:
str = str.intern();
adds the string to the internal pool if not already there, and returns a reference to the interned string. Interned strings can be compared with each other using ==, which is much cheaper than using equals() to do the comparison. String literals are always interned.

When you use
String str=new String("java world");
a string object is created out of the string literal pool , even if an equals string is already exists in the pool. Avoid new String unless you need it !

A JVM has string literal pool where it keep at most one object of the same type. String literal always refers to an object string literal pool. Since the object created with new String do not refer to objects in the String literal pool but you can made them with the help of String's intern() method.

java.lang.String.intern() return interned String i.e, one that has an entry in the global pool. If string is not already there, then it will be added.

Example of intern()

JVM is maintaining a table containing single reference to each unique string object in the global string pool ever created by an instance in order to optimize space. This means, there is always a reference to the String object in the string pool, therefore string object in the string pool is not eligible for garbage collection.



References:
https://www.ibm.com/developerworks
http://www.javapractices.com
https://stackoverflow.com
http://java-latte.blogspot.in

0 comments:

Post a comment

Contact

Get in touch with me


Adress/Street

Bangalore, India