• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Getting Wrong Output When Trying to Write a Program on HashMap

 
Sidharth Khattri
Ranch Hand
Posts: 125
Java Linux Scala
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
So, I was studying this topic: HashMap, when I decided to write a code for practice. It's almost like the one mentioned in K&B book, but I'm not getting the expected output. This is the code that I've written:



Getting Output:
dog key
null

Expected Output:
dog key
true

The hashCode() should find the bucket of size 6 and equals() should return true, why is the output null and not true?

But now, when I make a small change in the code(added a new line) I'm getting the correct Output. Why is it so?

Changed code:



Getting Output:
dog key
new dog key

Expected output:
dog key
new dog key

What difference does it make when I added that extra line in the code? Why is the code behaving this way?
 
Matthew Brown
Bartender
Posts: 4567
8
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Sidharth. Welcome to the Ranch!

I'm not certain this is the only cause, but I can see at least one thing you're doing wrong:
Never use == to compare Strings. Your equals() method doesn't work correctly. Try changing that and see is that changes the behaviour.

Oh, by the way: thanks for using code tags to display your code, but can you indent it consistently as well in future? It makes it much easier to read. Thanks!
 
Sidharth Khattri
Ranch Hand
Posts: 125
Java Linux Scala
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Matthew Brown wrote:Hi Sidharth. Welcome to the Ranch!

I'm not certain this is the only cause, but I can see at least one thing you're doing wrong:
Never use == to compare Strings. Your equals() method doesn't work correctly. Try changing that and see is that changes the behaviour.

Oh, by the way: thanks for using code tags to display your code, but can you indent it consistently as well in future? It makes it much easier to read. Thanks!


In K&B(SCJP Sun Certified Programmer for Java 6-0071591060) at Page Number 583 they have used == to compare strings:

That's why I used it. Although I was not sure as I thought string should be compared using equals() or equalsIgonreCase(). Nevertheless, it gives the same output, i.e, null.

I still don't get it.
And btw, thanks for quick reply and I'll make sure to indent it properly in future.
 
Matthew Brown
Bartender
Posts: 4567
8
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
OK, I've had a closer look, and I can see the problem now.

It's a bad idea to use mutable objects as keys in maps, and it's a bad idea to have equals() or hashCode() depend on mutable fields. What you've got there is a good demonstration why. The problem is this line:

When the original dog put in the map, the name is "tank". Which means the hash code is 4.

Then you change the name of the key to "clover". Now its hash code is 6. That means it isn't in the bucket of the HashMap that it ought to be in. So when you try to lookup the value, using an equal key, the HashMap looks in the 6 bucket and says "nothing there", and never finds the dog that's still in the 4 bucket.

Adding your extra line means that you do have the key in the right bucket - although now you'll have the same key in there twice, which isn't good. The other way you could get different behaviour is if you swap "clover" in both places for a four letter word. Now the key is still in the bucket it should be.

(Regardless of what K&B did in that example, you definitely should use equals(). It doesn't matter in this specific example because of the string pool and the fact that you are only using string literals that will all be put in the string pool).
 
Henry Wong
author
Marshal
Pie
Posts: 21226
81
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sidharth Khattri wrote:
In K&B(SCJP Sun Certified Programmer for Java 6-0071591060) at Page Number 583 they have used == to compare strings:

That's why I used it. Although I was not sure as I thought string should be compared using equals() or equalsIgonreCase(). Nevertheless, it gives the same output, i.e, null.

I still don't get it.
And btw, thanks for quick reply and I'll make sure to indent it properly in future.



Whether a string "should be compared using equals() or equalsIgonreCase()" is dependent on your program design. Do you want your program to consider upper case and lower case letters to be the same?

And as for your issue... the key of a hashmap should not change. When you changed the name of the dog from "tank" to "dog key", you changed the hashcode after an instance has been inserted. This means that it is very likely that the key is in the wrong bucket, and likely that the hashmap has been corrupted. Don't do that. Don't change key instances that has already been placed into the hashmap.

Henry
 
Sidharth Khattri
Ranch Hand
Posts: 125
Java Linux Scala
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks @Matthew Brown for your insightful explanation.
Can you please elucidate this line:
"Adding your extra line means that you do have the key in the right bucket - although now you'll have the same key in there twice, which isn't good. The other way you could get different behaviour is if you swap "clover" in both places for a four letter word. Now the key is still in the bucket it should be. "

At first, the key was "tank" having hashCode of 4, then I changed the key to clover having hashCode 6. Will "tank" key's bucket still exist? Or it's just that the "clover" key's bucket exists' now? How will there be same key twice?

I comprehended this from your explanation:
The value "dog key" is still in bucket with hashcode 4, but the key is changed to "clover" which created a new bucket with hashcode 6 and this bucket is empty. So when I try to get any value using the key "clover", it'll return null as there isn't anything in bucket with hashcode 6 which the key "clover" refers to.
And this line:

adds a new value "new dog key" to the bucket with hashcode 6, so when in the next line I try to get the value through the key "clover" I get an output "new dog key" because I added this new value to the bucket with hashcode 6.
Am I right?

@Henry Wong
And as for your issue... the key of a hashmap should not change. When you changed the name of the dog from "tank" to "dog key", you changed the hashcode after an instance has been inserted. This means that it is very likely that the key is in the wrong bucket, and likely that the hashmap has been corrupted. Don't do that. Don't change key instances that has already been placed into the hashmap.


I think I changed the name of dog from "tank' to "clover". I hope I'm not wrong. Still learning.
I changed the key that changed the hashcode, but which instance was inserted where? I don't get it
 
Henry Wong
author
Marshal
Pie
Posts: 21226
81
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sidharth Khattri wrote:Thanks @Matthew Brown for your insightful explanation.
Can you please elucidate this line:



To emphasize, what your code does is corrupt the hashmap... this means that it may still work (according to JavaDoc), this means that it may not, and of course, this means that any explanation may be moot. It may be true for one JVM but not another. It may be true for one platform, but not another. etc.

So... understand that any explanation given here is only currently true, and only for the version used by the person explaining. The discussion will be regarding implementation detail, and for a corrupted condition.

Anyway...
 
Henry Wong
author
Marshal
Pie
Posts: 21226
81
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sidharth Khattri wrote:
I comprehended this from your explanation:
The value "dog key" is still in bucket with hashcode 4, but the key is changed to "clover" which created a new bucket with hashcode 6 and this bucket is empty. So when I try to get any value using the key "clover", it'll return null as there isn't anything in bucket with hashcode 6 which the key "clover" refers to.


No. The HashMap doesn't know that. When you changed the key's state, nothing else changes. The key is still in the same bucket, which of course, may or may not be the correct bucket. Also, duplicate detection has not be done, so it may also be a duplicate. So, it may return null, as you explained, or it may still work -- if by chance the implementation maps the two hashcodes to the same bucket.

Henry

 
Sidharth Khattri
Ranch Hand
Posts: 125
Java Linux Scala
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I found the entire explanation for hashmap here:
http://howtodoinjava.com/2012/10/09/how-hashmap-works-in-java/

As a matter of fact, I think I got it right. I don't know why nobody is willing to ratify it in a more lucid manner. Or maybe I am partially/completely wrong.

Thanks Henry Wong for your replies.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic