Thursday, August 15, 2013

Sometime or always , people keep asking

1) Why we need equals method in model object?
2) Why we need hashCode method in model object?

Rather having answer , let's start with example directly:

public class Person {

private String name;
private String mobileNo;
public Person(String name, String mobileNo) {
this.name = name;
this.mobileNo = mobileNo;
}
//getter and setter
}
//let's create objects
Person person1= new Person("Chandu","1234567890");
Person person2= new Person("Chandu","1234567890");
//Even a lame will say,these two objects are same, let's check
if(person1.equals(person2)){
    System.out.println("Person are same in equal Method");
}
else
{
   System.out.println("Person are NOT same.");
}
//Output is
Person are NOT same.
//what the hell,how come?
Now Java doesn't see the obvious reason , the way we see it.We have to tell ,look, these two objects are same and don't apply your equals() as i m gonna write mine.

Add this under Person.java
@Override
public boolean equals(Object obj) {
if (this == obj)
 return true;
if (obj == null)
 return false;
if (getClass() != obj.getClass())
 return false;
Person other = (Person) obj;
 if (mobileNo == null) {
   if (other.mobileNo != null)
return false;
    } else if (!mobileNo.equals(other.mobileNo))
return false;
 if (name == null) {
   if (other.name != null)
return false;
    } else if (!name.equals(other.name))
     return false;
return true;

}

To cut long story short , this equals () says if this object name and mobile no are same with other object , objects are equal.

Lets run one more time and we get output:

Person are same in equal Method. //Nailed it.

So when we are writing our own model , we also need to give custom implementations for equals() based on our requirements.


So far , so good.

Let's tweak a little.
Add some piece of code in main method

Set<Person> personSet = new HashSet<Person>();
//A Set of person,Set doesn't allow duplicate entries.
//Means it will replace first object with second if they are equal.
personSet.add(person1);
personSet.add(person2);

//person1 and person2 in set, and we knew already ,these two objects were same.

System.out.println("Set size is " + personSet.size());

And output is : 
Set size is 2
//What the freak, size should be same 1 , though we added two objects but they //were equal.
What went wrong?

A clue is ,Collection objects works on hash.
What is hash()?It's a way to represent an object in numerical order.

Let's add some more code to our main()
System.out.println("HashCode for person1 " + person1.hashCode());
System.out.println("HashCode for person1 " + person2.hashCode());

My system o/p is :
HashCode for person1 1704434230
HashCode for person1 1141736277

If hash is a way representation of an object and if above two objects were same,then hash codes would had been same. But that's not the case here.

So in JAVA ,there is a saying 
If two objects are same by equals(), then hascode() for these objects should be same.

But in our case, it didn't happen.So what and where it went wrong?

This time we have to overwrite hashCode() in Person.java.
@Override
public int hashCode() {
final int prime = 31;//Always use prime number.
int result = 1;
result = prime * result
+ ((mobileNo == null) ? 0 : mobileNo.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;

}

Now Let's run main()
And output is :

Person are same in equal Methods
HashCode for person1 -1532305399
HashCode for person1 -1532305399
Set size is 1
//Finally,Nailed it.

That's what we wanted.

Thumb Rule,there is a silent contract b/w hashCode() and equals() :
  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

Enjoy Equal and Hashing!!!!.










Saturday, August 3, 2013

Reverse Function Tweak:


Well ,somebody asked "Can you write a little program of  reversing of a String without using StringBuffer or StringBuilder" ? Being a developer i said  hmmm, why not ,it's seems to be easy.
Started coding (we accept challenge instantaneously ), and believe me it was not. 

There are two ways that i am aware of  :
1)Simply use for loop and it's done(That was easy )

reverseString("Hello");//what we would do without "Hello"

public static void reverseString(String source){
if(source == null || source.length() == 0){
System.out.println("Source is Empty");
return;
}
char [] reverseArray = new char[source.length()];
for(int index = 0 ; index < reverseArray.length  ;index++){

reverseArray[index] = source.charAt(source.length() -1 - index);
        }
System.out.println(new String(reverseArray));

}

2) Use recursive function (Damn man, there is always another way).

System.out.println(recursiveReverseString("I love my Marantz amplifier with KEF Speakers"));//Really I do ;)

public static String  recursiveReverseString(String source){
   //This print statement will give us insight.
   System.out.println("***********" + source);
//Every recursive call should have a proper termination //call,otherwise prepare for java stackoverflowerror 
   if(source == null || source.length() <2){
System.out.println("Returning from here and source is       " + source);
return source;
 }
   return recursiveReverseString
(source.substring(1)) + source.charAt(0);
//substring always returns new String

}


I know last statement marked in yellow was little overdose.Printing statement will make it clear.
Here is print statement : 

***********I love my Marantz amplifier with KEF Speakers
*********** love my Marantz amplifier with KEF Speakers
***********love my Marantz amplifier with KEF Speakers
***********ove my Marantz amplifier with KEF Speakers
***********ve my Marantz amplifier with KEF Speakers
***********e my Marantz amplifier with KEF Speakers
*********** my Marantz amplifier with KEF Speakers
***********my Marantz amplifier with KEF Speakers
***********y Marantz amplifier with KEF Speakers
*********** Marantz amplifier with KEF Speakers
***********Marantz amplifier with KEF Speakers
***********arantz amplifier with KEF Speakers
***********rantz amplifier with KEF Speakers
***********antz amplifier with KEF Speakers
***********ntz amplifier with KEF Speakers
***********tz amplifier with KEF Speakers
***********z amplifier with KEF Speakers
*********** amplifier with KEF Speakers
***********amplifier with KEF Speakers
***********mplifier with KEF Speakers
***********plifier with KEF Speakers
***********lifier with KEF Speakers
***********ifier with KEF Speakers
***********fier with KEF Speakers
***********ier with KEF Speakers
***********er with KEF Speakers
***********r with KEF Speakers
*********** with KEF Speakers
***********with KEF Speakers
***********ith KEF Speakers
***********th KEF Speakers
***********h KEF Speakers
*********** KEF Speakers
***********KEF Speakers
***********EF Speakers
***********F Speakers
*********** Speakers
***********Speakers
***********peakers
***********eakers
***********akers
***********kers
***********ers
***********rs
***********s
Returning from here and source is       s

srekaepS FEK htiw reifilpma ztnaraM ym evol I


Which implementation I will go for? Well it depends which side of chair I am sitting on ,means weather I am taking an interview or giving one.

Couple of days back , I faced an issue with recursive call where i was navigating through millions of records , JVM didn't like it and threw stackoverflowerror.

Happy Tweaking!!!!









java.lang.String intern() tweak :


Why String.intern() is useful?

According to Java Docs

When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equal(object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.

Now let's tweak above statement by providing some example:

String string1 = "abc";//goes to String pool
//Create new String on heap ,not maintained by pool
String string2 = new String("abc");
String string3 = new String("abc").intern();//good practice ??

System.out.println(string1 == string2); //Of course false(pool vs heap)
System.out.println(string2 == string3);//False,
//string 3 is new but added to pool
//Next statement is worth looking for
System.out.println(string1 == string3);//True, how come??

Well java docs says after creating new String , string3 sits into pool and so is string 1 with same value hence returns true.

Now as developer we see ,it's quite useful to use intern because we will be saving memory as it will avoid holding duplicates entries of String in pool .
Till now everything looks good but(there is always , isn't it?) this also boils down some issues:

1) Locating or Searching a string over pool when there are millions of strings , might slows down searching.

2) String.intern() is native call ,so implementation/algorithm is behind curtain.


My take would be, to use intern() to avoid duplicates in pool and saving some memory and hence some bucks .

Friday, August 2, 2013

java.lang.String concat() tweak:


Java Doc says
   
        Concatenation happens  the specified string to the end of this string.
If the length of the argument string is 0, then this String object is returned. Otherwise, a new String object is created, representing a character sequence that is the concatenation of the character sequence represented by this String object and the character sequence represented by the argument string.


Saying that , how to implement our own concat().

Here is the sample:

 public static void concat(String firstString ,String secondString){

char [] firstStringarray = firstString.toCharArray();
char [] secondStringarray = secondString.toCharArray();
if(secondStringarray.length == 0){
System.out.println(firstString);
}else
{
       char [] newArray = new char[firstStringarray.length +                                       secondStringarray.length];
int index = 0;
while(index < firstStringarray.length){
newArray[index] = firstStringarray[index];
index ++;
}
while(index < newArray.length){
newArray[index] =         secondStringarray[secondStringarray.length (newArray.length - index)];                                 
index ++;
}
Sytem.out.println(new String(newArray));

}
}