HashMap (Java) giving wrong results - java

I have created a hash map in which each entry corresponds to 3 values
Key object values ( which are two in number)
I have created a class ,whose object i create and store the results in a hash map
This is my code below in which i compare my incoming data with the previous values in the hash map.If the same data comes then i just increment the counter of that data. I have taken the print statements in the the for loop . though the two strings match but still my code never comes in the if loop for increment the counter.Why?
for(i=1;i<=hMap.size();i++)
{
String skey = Integer.toString(i);
if(hMap.get(skey).olddata==comingdata)
{
hMap.get(skey).counter= hMap.get(skey).counter+1;
}
}

You haven't given nearly enough information about the types involved, but, but I strongly suspect that this is the problem:
if(hMap.get(skey).olddata==comingdata)
That will be comparing references, rather than for equality, if olddata and comingdata are references of some kind. (EDIT: By the sounds of it, they're string references.)
My guess is that you want:
String skey = Integer.toString(i);
if(hMap.get(skey).olddata.equals(comingdata))
{
hMap.get(skey).counter= hMap.get(skey).counter+1;
}
Or rather more efficiently, avoiding pointless lookups:
WhateverType value = hMap.get(Integer.toString(i));
if (value.olddata.equals(comingdata))
{
value.counter++;
}
I'd also suggest that if you're always going to look up by an integer, why not use an Integer key instead of always converting the integer into a string?
Additionally, it's worth following Java naming conventions, and you should make your fields private if they're not already.
If none of this helps, please post more code. The chances of the problem being in HashMap rather than in your code are incredibly small.

It's not clear the type of olddata, but maybe you should compare the values using equals():
if (hMap.get(skey).olddata.equals(comingdata))
In Java, == is used for either comparing primitive data types for equality or comparing object types for identity. If you need to compare two object types for equality, then you must use the equals() method, which is defined for all objects since it's inherited from the Object class, being aware that you also must override equals() and hashCode() in your class, providing implementations meaningful for that class.

You don't compare objects with == in Java unless you're trying to see if they have the same reference value.
if (hMap.get(skey).olddata.equals(comingdata)) {
...
You also shouldn't be exposing olddata like that; it should be available via a getter; e.g. getOldData()

It should be
if(hMap.get(skey).olddata.equals(comingdata))

Do you actually mean comingdata.equals(hMap.get(skey).olddata)? Furthermore be aware that equals(Object) and hashCode() must be correclty implemented.

Related

Why does Java need equals() if there is hashCode()?

If two objects return same hashCode, doesn't it mean that they are equal? Or we need equals to prevent collisions?
And can I implement equals by comparing hashCodes?
If two objects have the same hashCode then they are NOT necessarily equal. Otherwise you will have discovered the perfect hash function. But the opposite is true - if the objects are equal, then they must have the same hashCode.
hashCode and Equals are different information about objects
Consider the analogy to Persons where hashcode is the Birthday,
in that escenario, you and many other people have the same b-day (same hashcode), all you are not the same person however..
Why does Java need equals() if there is hashCode()?
Java needs equals() because it is the method through which object equality is tested by examining classes, fields, and other conditions the designer considers to be part of an equality test.
The purpose of hashCode() is to provide a hash value primarily for use by hash tables; though it can also be used for other purposes. The value returned is based on an object's fields and hash codes of its composite and/or aggregate objects. The method does not take into account the class or type of object.
The relationship between equals() and hashCode() is an implication.
Two objects that are equal implies that the have the same hash code.
Two objects having the same hash code does not imply that they are equal.
The latter does not hold for several reasons:
There is a chance that two distinct objects may return the same hash code. Keep in mind that a hash value folds information from a large amount of data into a smaller number.
Two objects from different classes with similar fields will most likely use the same type of hash function, and return equal hash values; yet, they are not the same.
hashCode() can be implementation-specific returning different values on different JVMs or JVM target installations.
Within the same JVM, hashCode() can be used as a cheap precursor for equality by testing for a known hash code first and only if the same testing actual equality; provided that the equality test is significantly more expensive than generating a hash code.
And can I implement equals by comparing hashCodes?
No. As mentioned, equal hash codes does not imply equal objects.
The hashCode method as stated in the Oracle Docs is a numeric representation of an object in Java. This hash code has limited possible values (represented by the values which can be stored in an int).
For a more complex class, there is a high possibility that you will find two different objects which have the same hash code value. Also, no one stops you from doing this inside any class.
class Test {
#Override
public int hashCode() {
return 0;
}
}
So, it is not recommended to implement the equals method by comparing hash codes. You should use them for comparison only if you can guarantee that each object has an unique hash code. In most cases, your only certainty is that if two objects are equal using o1.equals(o2) then o1.hashCode() == o2.hashCode().
In the equals method you can define a more complex logic for comparing two objects of the same class.
If two objects return same hashCode, doesn't it mean that they are equal?
No it doesn't mean that.
The javadocs for Object state this:
The general contract of hashCode is:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently
return the same integer, provided no information used in equals
comparisons on the object is modified. ...
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.
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCodemethod on
each of the two objects must produce distinct integer results. ...
Note the highlighted statement. It plainly says "No" to your question.
There is another way to look at this.
The hashCode returns an int.
There are only 232 distinct values that an int can take.
If a.hashCode() == b.hashCode() implies a.equals(b), then there can be only 232 distinct (i.e. mutually unequal) objects at any given time in a running Java application.
That last point is plainly not true. Indeed, it is demonstrably not true if you have a large enough heap to hold 232 instances of java.lang.Object ... in a 64-bit JVM.
And a third way is to some well-known examples where two different two character strings have the same hashcode.
Given that your assumption is incorrect, the reasoning that follows from it is also incorrect.
Java does need an equals method.
You generally cannot implement equals using just hashCode.
You may be able to use hashCode to implement a faster equals method, but only if calling hashCode twice is faster than comparing two objects. It generally isn't.
hashCodes are equal -> Objects might be equal -> further comparision is required
hashCodes are different -> Object are not equal (if hashCode is implemented right)
That's how equals method are implemented. At first you check if hashCodes are equal. If yes, you need to check class fields to see if it represents the exact same object. If hashCodes are different, you can be sure that objects are not equal.
Sometimes (very often?) you don't!
These answers are not untrue. But they don't tell the whole story.
One example would be where you are creating a load of objects of class SomeClass, and each instance that is created is given a unique ID by incrementing a static variable, nInstanceCount, or some such, in the constructor:
iD = nInstanceCount++;
Your hash function could then be
int hashCode(){
return iD;
}
and your equals could then be
boolean equals( Object obj ){
if( ! ( obj instanceof SomeClass )){
return false;
}
return hashCode() == obj.hashCode();
}
... under such circumstances your idea that "equals is superfluous" is effectively true: if all classes behaved like this, Java 10 (or Java 23) might say, ah, let's just get rid of silly old equals, what's the point? (NB backwards compatibility would then go out the window).
There are two essential points:
you couldn't then create more than MAXINT instances of SomeClass. Or... you could ... if you set up a system for reassigning the IDs of previously destroyed instances. IDs are typically long rather than int ... but this wouldn't work because hashCode() returns int.
none of these objects could then be "equal" to another one, since equality = identity for this particular class, as you have defined it. Often this is desirable. Often it shuts off whole avenues of possibilities...
The necessary implication of your question is, perhaps, what's the use of these two methods which, in a rather annoying way, have to "cooperate"? Frelling, in his/her answer, alluded to the crucial point: hash codes are needed for sorting into "buckets" with classes like HashMap. It's well worth reading up on this: the amount of advanced maths that has gone into designing efficient "bucket" mechanisms for classes like HashMap is quite frightening. After reading up on it you may come to have (like me) a bit of understanding and reverence about how and why you should bother implementing hashCode() with a bit of thought!

Correct implementation of hashcode/equals

I have a class
class Pair<T>{
private T data;
private T alternative;
}
Two pair objects would be equal if
this.data.equals(that.data) && this.alternative.equals(that.alternative) ||
this.data.equals(that.alternative) && this.alternative.equals(that.data)
I'm having difficulty correctly implementing the hashCode() part though. Any suggestions would be appreciated
You should use the hashCode from data and alternative like this :
return this.data.hashCode() + this.alterative.hashCode();
Although it is not the best approach, as if you change the data or alternative, then their hashcode will also change. Think a little bit and see if you really need to use this class as a key in a map and if not a Long or String would be a better candidate.
This should do the trick:
#Override
public int hashCode() {
return data.hashCode() * alternative.hashCode();
}
Since you want to include both fields into the equals, you need to include both fields into the hashCode method. It is correct if unequal objects end up having the same hash code, but equal objects according to your scheme will always end up having the same hash code with this method.
Refer to the java doc, the general contract of hashCode is(copied from java doc):
- Whenever it is invoked on the same object more than once during an
execution of a Java application, the hashCode method must
consistently return the same integer, provided no information used in
equals comparisons on the object is modified. This integer need not
remain consistent from one execution of an application to another
execution of the same application.
- 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.
- It is not required that if two objects are unequal according to the
equals(java.lang.Object) method, then calling the hashCode method on
each of the two objects must produce distinct integer results.
However, the programmer should be aware that producing distinct
integer results for unequal objects may improve the performance of
hashtables.
So from your implementation of equals, data and alternative are switchable. So you need make sure in your hashCode implementation returns the same value if you switch the position of data.hashCode() and alternative.hashCode(). If you are not sure, just return a const value such as 1 (But it may cause performance issue when you try to put the object into a Map).

Hashmap gives Null when trying to get an objects that exists in it [duplicate]

This question already has answers here:
Why do I need to override the equals and hashCode methods in Java?
(31 answers)
Closed 7 years ago.
I am running into this weird issue where I am iterating over a list of responses. when I try to get the answer from each response by the question, most of them get the answer correctly except one where getting the answer from the hashmap gives null. I have ran the debug mode in eclipse, and compared the question that I try to get its value from the hashmap getAnswerMap() with the one inside that hashmap and both seem to be exactly the same, but I still get null.
for (SurveyResponse response : responses) {
MultipleChoiceAnswer answer = (MultipleChoiceAnswer) response.getAnswerMap().get(question);
....
....
}
Then, I thought it is a hashcode issue, so I added another ugly line of code to check hashcodes, and they actually have the same hashcode and the additional following line worked and did set answer correctly.
for (SurveyResponse response : responses) {
MultipleChoiceAnswer answer = (MultipleChoiceAnswer) response.getAnswerMap().get(question);
for (Entry entry: response.getAnswerMap().entrySet()) {
if (entry.getKey().hashCode() == question.hashCode()) answer = (MultipleChoiceAnswer) entry.getValue();
....
....
}
However, this is very ugly and I would really like to get the answer correctly from the hashmap. Any suggestions?
UPDATE:
calling both hashCode() and equals() method on both objects shows that both have equal hashcodes and equals() returns true. I suspect that as one of the answers down indicate, the problem might be that the question was inserted with a different hashcode when it was inserted in the hashmap. Therefore, calling the get method in question returns null because the object I am trying to get does not have the same hashcode as the old one. Extremely helpful answers guys!
One thing to watch out for: Make sure the class you're using as a key is immutable -- otherwise, a key will hash to one thing when you put it in, but something different when you take it out.
Edit: It doesn't have to be immutable, but it has to be true that it can only be changed in a way that doesn't change the hashcode. Making the entire object immutable is the simplest way to do that, but it's not the only way.
One more glass ball guess:
You have an equals method like this one:
class Question {
// ...
public boolean equals(Question q) {
// do intelligent comparison
}
public int hashCode() {
// calculate hash code
}
}
But here you don't really override the equals(Object) method from Object, but simply declare a new one beside this. The HashMap does not know anything about your new method, it will simply call the original one for comparing your key object in the map with the query key (after finding one with matching hashCode).
Declare the method like this, instead:
#Override
public boolean equals(Object o) {
if(! (o instanceof Question))
return false;
Question q = (Question)o;
// do intelligent comparison
}
(The #Override annotation lets the compiler check that you are really overriding a method here, not just creating a new one.)
To make an object an 100% deterministic key with a HashMap you need to override hashCode() and equals() where they are consistent in that equals() always returns true when the hashCode()s are the same.
Here is an old article from Brian Goetz on IBM developerWorks, but the contents are still applicable today:
Why override equals() and hashCode()?
What would happen if Integer did not
override equals() and hashCode()?
Nothing, if we never used an Integer
as a key in a HashMap or other
hash-based collection. However, if we
were to use such an Integer object for
a key in a HashMap, we would not be
able to reliably retrieve the
associated value, unless we used the
exact same Integer instance in the
get() call as we did in the put()
call. This would require ensuring that
we only use a single instance of the
Integer object corresponding to a
particular integer value throughout
our program. Needless to say, this
approach would be inconvenient and
error prone.
The interface contract
for Object requires that if two
objects are equal according to
equals(), then they must have the same
hashCode() value. Why does our root
object class need hashCode(), when its
discriminating ability is entirely
subsumed by that of equals()? The
hashCode() method exists purely for
efficiency. The Java platform
architects anticipated the importance
of hash-based collection classes --
such as Hashtable, HashMap, and
HashSet -- in typical Java
applications, and comparing against
many objects with equals() can be
computationally expensive. Having
every Java object support hashCode()
allows for efficient storage and
retrieval using hash-based
collections.
It's likely that you haven't overridden equals(..) correctly - it is a requirement for a HashMap to work correctly

Setting key type in HashMap, how?

hi
I want to create a HashMap (java) that stores Expression, a little object i've created.
How do I choose what type of key to use? What's the difference for me between integer and String? I guess i just don't fully understand the idea behind HashMap so i'm not sure what keys to use.
Thanks!
Java HashMap relies on two things:
the hashCode() method, which returns an integer that is generated from the key and used inside the map
the equals(..) method, which should be consistent to the hash calculated, this means that if two keys has the same hashcode than it is desiderable that they are the same element.
The specific requirements, taken from Java API doc are the following:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
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.
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.
If you don't provide any kind of specific implementation, then the memory reference of the object is used as the hashcode. This is usually good in most situations but if you have for example:
Expression e1 = new Expression(2,4,PLUS);
Expression e2 = new Expression(2,4,PLUS);
(I don't actually know what you need to place inside your hashmap so I'm just guessing)
Then, since they are two different object although with same parameters, they will have different hashcodes. This could be or not be a problem for your specific situation.
In case it isn't just use the hasmap without caring about these details, if it is you will need to provide a better way to compute the hashcode and equality of your Expression class.
You could do it in a recursive way (by computing the hashcode as a result of the hashcodes of children) or in a naive way (maybe computing the hashcode over a toString() representation).
Finally, if you are planning to use just simple types as keys (like you said integers or strings) just don't worry, there's no difference. In both cases two different items will have the same hashcode. Some examples:
assert(new String("hello").hashCode() == new String("hello").hashCode());
int x = 123;
assert(new Integer(x).hashCode() == new Integer(123).hashCode());
Mind that the example with strings is not true in general, like I explained you before, it is just because the hashcode method of strings computes the value according to the content of the string itself.
The key is what you use to identify objects. You might have a situation where you want to identify numbers by their name.
Map<String,Integer> numbersByName = new HashMap<String,Integer>();
numbersByName.put("one",Integer.valueOf(1));
numbersByName.put("two",Integer.valueOf(2));
numbersByName.put("three",Integer.valueOf(3));
... etc
Then later you can get them out by doing
Integer three = numbersByName.get("three");
Or you might have a need to go the other way. If you know you're going to have integer values, and want the names, you can map integers to strings
Map<String,Integer> numbersByValue = new HashMap<String,Integer>();
numbersByValue.put(Integer.valueOf(1),"one");
numbersByValue.put(Integer.valueOf(2),"two");
numbersByValue.put(Integer.valueOf(3),"three");
... etc
And get it out
String three = numbersByValue.get(Integer.valueOf(3));
Keys and their associated values are both objects. When you get something from a HashMap, you have to cast it to the actual type of object it represents (we can do this because all objects in Java inherit the Object class). So, if your keys are strings and your values are Integers, you would do something like:
Integer myValue = (Integer)myMap.get("myKey");
However, you can use Java generics to tell the compiler that you're only going to be using Strings and Integers:
HashMap<String,Integer> myMap = new HashMap<String,Integer>();
See http://download.oracle.com/javase/1.4.2/docs/api/java/util/HashMap.html for more details on HashMap.
If you do not want to look up the expressions, why do you want them to store in a map?
But if you want to, then the key is that item you use for lookup.

Convert string to hash and then reform the string later

I need to hash some strings so I can pass them into some libraries, this is straight forward using the String.hashCode call.
However once everything is processed I'd like to convert the integer generated from the hashCode back into the String value. I could obviously track the string and hashcode values somewhere else and do the conversion there, but I'm wondering is there anything in Java that will do this automatically.
I think you misunderstand the concept of a hash. A hash is a one way function. Worse, two strings might generate the same hash.
So no, it's not possible.
hashCode() is a not generally going to be a bijection, because it's not generally going to be an injective map.
hashCode() has ints as its range. There are only 2^32 distinct int values, so for any object where there there can be more than 2^32 different ones (e.g., think about Long), you are guaranteed (by the pigeonhole principle that at least two distinct objects will have the same hash code.
The only guarantee that hashCode() gives you is that if a.equals(b), then a.hashCode() == b.hashCode(). Every object having the same hash code is consistent with this.
You can use the hashCode() to uniquely identify objects in some very limited circumstances: You must have a particular class in where there are no more than 2^32 possible different instances (i.e., there are at most 2^32 objects of your class which pairwise are such that !a.equals(b)). In that case, so long as you ensure that whenever !a.equals(b) and both a and b are objects of your class, that a.hashCode() != b.hashCode(), you will have a bijection between (equivalence classes of) objects and hash codes. (It could be done like this for the Integer class, for example.)
However, unless you're in this very special case, you should create a unique id some other way.
That is not possible in general. The hashCode is what one would call a one-way-function.
Besides, there are more strings than integers, so there is a one-to-many mapping from integers to strings. The strings "0-42L" and "0-43-" for instance, have the same hash-code. (Demonstration on ideone.com.)
What you could do however, (as an estimate), would be to store the strings you pass into the API and remember their hash-codes like this:
import java.util.*;
public class Main {
public static void main(String[] args) {
// Keep track of the corresponding strings
Map<Integer, String> hashedStrings = new HashMap<Integer, String>();
String str1 = "hello";
String str2 = "world";
// Compute hash-code and remember which string that gave rise to it.
int hc = str1.hashCode();
hashedStrings.put(hc, str1);
apiMethod(hc);
// Get back the string that corresponded to the hc hash code.
String str = hashedStrings.get(hc);
}
}
Not possible to convert the .hashcode() output to the original form. It's a one way process.
You can use a base64 encoder scheme where you will encode the data, use it where ever you want to and then decode it to the original form.

Categories

Resources