Monday, December 26, 2016

String Handling in Java

Definition:
String is nothing but a sequence of characters (not the collection of characters). An array is the only way to represent any sequence characters. Java internally assigns a char array inside String object. A String looks like an object but internally it is an array and it never terminate with null.

There are 4 classes in java to represent a string:
1)    Java.lang.String – used mostly in general programs.
2)    Java.lang.StringBuffer – used mostly in general programs.
3)    Java.lang.StringBuilder – used mainly in multithreading
4)    java.util.StringTokenizer – used in input output (IO).

A String is an immutable object, which means once a value is assigned we cannot make any changes in it (append, insert, replace, delete). We can print, count, compare etc. but modification is not allowed. Whereas we can accomplish such tasks in StringBuffer, which means StringBuffer is a mutable object, we can perform update operations in it like append, insert, replace, delete etc.

String s = “hello”;
StringBuffer sb = “hello”;

Both of above will create an object internally, among them s is not allowed to be modified where as sb is allowed to be modified.
Now, s = s + “ world”;

Is this statement not allowed? Is allowed then can we say this is a modification in s?

The answer is NO, here as soon as we are concatenating “ world” in existing string object the old string object is completely destroyed from memory and a new object is created with the value “hello world”.

Now, about the sb object. Here we have set of methods like append(), delete(), replace(), insert() etc. which directly update the values in existing object.

Detail about String class:
There are 2 ways to declare String class object:
String msg = “hello”;
String msg = new String(“hello”);

Rule – by default all integer laterals are treated as an int, similarly by default all floating laterals are treated as double. But, by default an string lateral is treated as object. Anything which is in double quotes are treated as String class object. for example “hello”.length(); is valid in java.

All String objects created through new operator is stored in heap memory area where as the String object created using lateral is stored in special memory area known as “String constant pool”.

e.g. String msg = “Hello World”;

for above line of code the JVM will first check the existence of same object “Hello World” and if it exists the it will return the reference of this object. Now as we know it is immutable so it will create just one memory area and give its reference to all.

Rule – String constant pool never contains the duplicate object of String class whenever they are created through laterals.

Rule2 – the garbage collection is not applicable for the String class objects which are allocated in String constant pool (through laterals), even if they are unreachable. The JVM gives the reference of those objects when there is a new request for same object.

Rule3 – whenever we create a String object using new operator and we pass a string in double quote, it means the JVM will create two objects, on in heap area and another in String constant pool area.  
For example:
String msg = new String(“hello”);

For above statement the JVM will create an object in heap area because new operator is used. but there is a lateral value “hello” passed inside, so it will create one more object at string constant pool area(SCP), and the reference id of object at heap will be returned to the user not the SCP one.

There is a method of String class named as intern(), this method is used to get the reference id of object allocated at SCP area, if it does not exists this method will return null.

Constructors of String class:
1) default constructor – when we create string object using default constructor then there is no use of such objects because it will actually create a blank object and it will be immutable so there is no use of it.

2) String(String s) – it will accept a laterals and will create another object with that lateral object.
char a[] = {‘a’,’b’,’c’};
String msg = new String(a);

3) String(byte[] b)


String Comparison:

There are 3 methods provided in String class for string comparison: equals(), equalsIgnoreCase(), compareTo()
equals() and equalsIgnoreCase() belogs to the Object class which are overridden by String class.

Here is the syntax and example of Object class equals() method:
boolean equals(Object o);

package dev21century.string;

public class Temp
{
       public static void main(String args[])
       {
              Temp temp1 = new Temp();
              Temp temp2 = new Temp();
             
              boolean result = temp1.equals(temp2);
              System.out.println("result = " + result);
       }
}

Output:
result = false

First it will take the reference id of both objects and compare their values internally using == operator.

Now, lets take a look of String class equals() method (Overridden from Object class):

e.g.
package dev21century.string;

public class Temp
{
       public static void main(String args[])
       {
              String msg = "hello"//this object will be allocated in SCP (String Constant Pool) area.
              String msg2  = new String("hello"); //this object will be allocated in heap area.
              boolean result = msg.equals(msg2);

              System.out.println("result = " + result);
       }
}

Output:
result = true

in above program the JVM will compare the contents of object, not the reference ids. It matches the values of string no matter if its stored in heap or in SCP area. In SCP area the duplication is not possible but in heap area it is possible. equals() comparison is a case sensitive comparison.

Quick Question –
package dev21century.string;

public class Temp
{
       public static void main(String args[])
       {
              String msg = "hello";
              String msg2new String("hello");
              Temp temp1 = new Temp();

              boolean result = msg.equals(temp1);
              System.out.println("result =" + result);

       }
}

Is it possible, is there any compilation error when we try to compare a string object with another non string object?

Answer – No compilation error, it will run fine and result will be false. Internally it will be internally treated as follows:
If(o instanceof String)
{
//comparison code
}
Else
return false;

equalsIgnoreCase() example – as its name suggests, it will ignore the case while comparing:

package dev21century.string;

public class Temp
{
       public static void main(String args[])
       {
              String msg = "hello";
              String msg2= new String("Hello");

              boolean result = msg.equalsIgnoreCase(msg2);
              System.out.println("result =" + result);

       }
}

Output:
result =true

String comparison using compareTo() method:

package dev21century.string;

public class Temp
{
       public static void main(String args[])
       {
              String msg = "hello";
              String msg2= new String("hello");

              int result = msg.compareTo(msg2);
             
              System.out.println("result =" + result);

       }
}

Output:
result =0

The compareTo() method takes the characters one by one and get its ASCII value then it subtracts (-) them and if it result as zero for all characters which means both strings are identical, so as a result it returns 0. But if difference found at any point, it returns any positive value.

compareToIgnoreCase() method do a case insensitive comparison.


toUpperCase() & toLowerCase() method example:

package dev21century.string;

public class Temp
{
  public static void main(String args[])
   {
     String msg = "save water and trees for safe life.";
             
     msg = msg.toUpperCase();         
     System.out.println("result = " + msg);

     String msg2 = "KEEP ENVIRONMENT CLEAN";
             
     msg2 = msg2.toLowerCase();       
     System.out.println("result = " + msg2);
             
   }
}

Output:

trim() method:

trim() method trims the leading and trailing spaces.
package dev21century.string;

public class Temp
{
 public static void main(String args[])
 {
  String msg = "          save water and trees for safe life.           ";
             
  System.out.println("Before triming = " + msg);
  System.out.println("After triming = " + msg.trim());
             
 }
}

Output:

length() method – it gives length of string.
package dev21century.string;

public class Temp
{
       public static void main(String args[])
       {
              String msg = "hello";
              System.out.println("Length = " + msg.length());
       }
}

Output:
Length = 5


substring() method:

package dev21century.string;

public class Temp
{
 public static void main(String args[])
  {
   String msg = "save water and trees for safe life.";
   System.out.println(msg.substring(5));
   //Will start from 5th position (starting 0) and return rest all
   System.out.println(msg.substring(5, 10));
             
  }
}

Output:

indexOf() method:

this method will return index value of any character supplied to this method. If not found then it will return -1. By default it will start looking the character from 0thposition however we can also supply the start position. If character is repeated then it will return the position of first occurrence.

Example:
package dev21century.string;

public class Temp
{
 public static void main(String args[])
 {
  String msg = "save water and trees for safe life.";
  System.out.println("Index of 1 is: " + msg.indexOf(1));
  System.out.println("Index of w is: " + msg.indexOf('w'));
  System.out.println("Index of e is: " + msg.indexOf('e'));
  System.out.println("Index of e starting from 11th position: " + msg.indexOf('e', 11));
  System.out.println("Index of trees: " + msg.indexOf("trees", 0)); //case sensitive
  System.out.println("Index of safe: " + msg.indexOf("safe")); //case sensitive
 }
}

Output:

lastIndexOf() method:
this is similar to the indexOf() method, the difference is lastIndexOf() will start looking from last.

Example:
package dev21century.string;

public class Temp
{
 public static void main(String args[])
  {
   String msg = "save water and trees for safe life.";
   System.out.println("Index of 1 is: " + msg.lastIndexOf(1));
   System.out.println("Index of w is: " + msg.lastIndexOf('w'));
   System.out.println("Index of e is: " + msg.lastIndexOf('e'));
   System.out.println("Index of e starting from 11th position: " + msg.lastIndexOf('e', 11));
   System.out.println("Index of trees: " + msg.lastIndexOf("trees", 50)); //case sensitive
   System.out.println("Index of safe: " + msg.lastIndexOf("safe")); //case sensitive
  }
}

Output:

StringBuffer class:

StringBuffer is similar to the String class with some differences like:
1) StringBuffer is mutable which means data can be modified dynamically.
2) laterals are not allowed in StringBuffer for example following statement will give compilation error:
StringBuffer sb = "hello";

StringBuffer sb = new StringBuffer();
Above line of code will by default allocate 16 byte memory in heap area to store the string. We can cross check it by using sb.capacity() method. This method will return 16. There is a length() method which will return zero as of now because there is no character in this object.

Lets take this small example:
package dev21century.string;

public class Temp
{
  public static void main(String args[])
   {
     StringBuffer sb = new StringBuffer();
     System.out.println("capacity : " + sb.capacity());
     System.out.println("length : " + sb.length());
             
     sb.insert(0, "Hello");
     sb.append(" World");
     System.out.println("length after inserting string: " + sb.length());
     System.out.println(sb);
             
   }
}

Output:

In StringBuffer object when we put more than 16 characters, it does not give any error, instead it uses the ‘growing array dynamically’ concept to increase the size of its array. JVM actually creates a new bigger array (increase by 18 bytes) and copy older data into new one and older array becomes available for garbage collection.

We can also provide initial capacity –
StringBuffer sb = new StringBuffer(50);

Now, its capacity is 50 and length is zero.
package dev21century.string;

public class Temp
{
  public static void main(String args[])
   {
     StringBuffer sb = new StringBuffer(50);
     System.out.println("Capacity: " + sb.capacity());
     System.out.println("Initial length: " + sb.length());
     sb.insert(0, "I Java");
     sb.insert(1, " Love");
     System.out.println(sb);
     sb.replace(2, 6, "Like");
     System.out.println(sb);
     sb.delete(2, 7);
     System.out.println(sb);
   }
}

Output:

No comments:

Post a Comment