Thursday, March 29, 2012

HashMap stores value by reference. Rare Programming Error

HashMap is one of most widely used collection classes in java. Inserting objects into hashmap is very common task every java developer do.However we do forget to get into depth way in which hashmap stores the values. This might led to serious issues with our code. Below is simple piece of code. Try guessing its output

  StringBuffer sb = new StringBuffer("AA");
  Map m = new HashMap();
  m.put("A", sb);
  sb.append("AAA");
  m.put("B", sb);
  Iterator it = m.entrySet().iterator();
  while (it.hasNext()) 
                {
   Map.Entry pairs = (Map.Entry) it.next();
   System.out.println(pairs.getKey() + " = " + pairs.getValue());
  }
  sb.append("CCCCC");
  System.out.println("HashMap entry after String buffer is modified further");
  it = m.entrySet().iterator();
  while (it.hasNext())
                {
   Map.Entry pairs = (Map.Entry) it.next();
   System.out.println(pairs.getKey() + " = " + pairs.getValue());
  }

 
many of you might predict output to be
A = AA
B = AAAAA
HashMap entry after String buffer is modified further
A = AA
B = AAAAA
But to your surprise if you run above piece of code output would be
A = AAAAA
B = AAAAA
HashMap entry after String buffer is modified further
A = AAAAACCCCC
B = AAAAACCCCC

Actually what happens is Hash map stores object by reference and dosent make copy of object when you say m.put(Object o). So if the reference o gets modified then Entry inside hashmap also would get modified
So whenever you are inserting some data into Hashmap ensure that either object is mutable ie it will create fresh instance if it undergoes modification else you need to ensure that same reference is not modified anywhere else in program effecting the data in hashmap.

5 comments:

Developer Dude said...

The real thing to remember is that if you are keying on some value in the object then:

myObject.setName("Name X");
myHashMap.put(myObject.getName(), myObject);
myObject.setName("Name 123);
System.out.println(myHashMap.get("Name X");

Returns what??

Null

Unknown said...

No
If myObject is instance of immutable class when u modify one more intance will get created.But old instance will have referece of hashmap so will not go for garbage collection. So will nt return null
However if it is mutable u will get myObject instance with modified setname parameter. Remeber Value is stored by reference not key

javin paul said...

Good post. by the way keys should be immutable if not than if you ensure equals() and hashcode() should use immutable fields. I have shared few points on my post How HashMap works in Java you may like

Ramya said...

Superb post.Spent a whole day when I was pulling my hair sorting out the issue..Thanks

Manna Anam said...

https://stackoverflow.com/questions/57380797/cannot-reach-a-temp-table-using-java-sql-statement-object-passed-as-a-map-value

This Statement object was not modified but the temp table created by Statement connection isn't reachable when passed within HashMap. This seems like stack reference when passed inside within a map object vs a method parameter is totally different. Hence, the inability to reach the temp table?