Reputation: 11
I have Pair class in my project and I am using hashtable in my application. After constructing my hashtable, I test that the Pair objects are created and store correctly in the hashtable by printing the content of the the hash, and immediately I am trying to get one of the values using get(key) method, and it always gives me null.
This is my whole Class, Mapping which has a private object of type hashtable package metastore;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;
import org.apache.hadoop.hive.ql.parse.ASTNode;
import preprocessingQuery.Pair;
public class Mapping {
private Hashtable<Pair, Pair> hashTable ;
public Mapping(){
hashTable= new Hashtable<Pair, Pair>();
}
public Hashtable<Pair, Pair> getHashTable() {
return hashTable;
}
public void setHashTable(Hashtable<Pair, Pair> hashTable) {
this.hashTable = hashTable;
}
public Pair getMapping( Pair originalPair) {
Pair mappedPair=(hashTable.get(originalPair));
return mappedPair;
}
public ArrayList<Mapping> getPairs(ASTNode an){
ArrayList<Mapping> pairs=new ArrayList<Mapping>();
return pairs;
}
public void print() {
Enumeration<Pair> contentOfHT;
contentOfHT = hashTable.keys();
while(contentOfHT.hasMoreElements()) {
Object str = contentOfHT.nextElement();
System.out.println(str + "\tis mapped to " +
hashTable.get(str));
}
}
public void loadMappingTable() {
String originalTable;
String originalCol;
String mappedTable;
String mappedCol;
Pair originalPair;
Pair mappedPair;
BufferedReader in = null;
try {
in = new BufferedReader(
new FileReader(
"D:\\Documents and Settings\\QUAdmin.STAFF\\Desktop\\mapping.txt"));
String line ;
while ((line = in.readLine()) != null) {
StringTokenizer stok = new StringTokenizer(line, "\t");
originalTable= stok.nextToken();
originalCol= stok.nextToken();
mappedTable= stok.nextToken();
mappedCol= stok.nextToken();
originalPair=new Pair(originalTable,originalCol);
mappedPair=new Pair(mappedTable,mappedCol);
hashTable.put(originalPair, mappedPair);
}
} catch (Exception ex) {
// catch all exceptions as one. This is bad form imho
ex.printStackTrace();
} finally {
try {
if (in != null)
in.close();
} catch (IOException ex) {
}
}
}
public static void main(String[] args)
{
Mapping map=new Mapping();
map.loadMappingTable();
System.out.println("Size: "+ map.getHashTable().size());
System.out.println("The content of the hash table");
map.print();
System.out.println("Testing the mapping");
Pair originalPair=new Pair("table1","table1_name");
System.out.println(map.getMapping(originalPair));
System.out.println(map.getHashTable().get(originalPair));
System.out.println(map.getHashTable());
}
}//end of Mapping Class
And this is the output
Size: 3
The content of the hash table
[table=table1, col=table1_age] is mapped to [table=table1_SNT, col=table1_SNT_age]
[table=table1, col=table1_name] is mapped to [table=table1_SNT, col=table1_SNT_name]
[table=table1, col=table1_id] is mapped to [table=table1_SNT, col=table1_SNT_id]
Testing the mapping
null
null
{[table=table1, col=table1_age]=[table=table1_SNT, col=table1_SNT_age], [table=table1, col=table1_name]=[table=table1_SNT, col=table1_SNT_name], [table=table1, col=table1_id]=[table=table1_SNT, col=table1_SNT_id]}
Thanks
Upvotes: 1
Views: 3516
Reputation: 37435
I'd need to see your implementation of Pair. My guess is that you are not correctly implementing equals and hashcode.
[Edit]
Given your implementation of Pair (taken from the comments)
package preprocessingQuery;
public class Pair {
private String table;
private String col;
public Pair(String table, String col) {
super();
this.table = table;
this.col = col;
}
public String getTable() {
return table;
}
public void setTable(String table) {
this.table = table;
}
public String getCol() {
return col;
}
public void setCol(String col) {
this.col = col;
}
@Override public String toString() {
return "[table=" + table + ", col=" + col + "]";
}
}
You are indeed missing equals and hashcode. Some background: The default implementation of Object.equals and Object.hashCode are based on the memory address of the object (Object reference). From that perspective, all your Pairs are all different as they are different objects.
For any collection implementation to work properly, you need to override the default implementation of equals and hashCode of the objects to be stored in the collection.
For your Pair class, it should look something like this:
@Override
public boolean equals(Object other) {
if (this == other) {
return true; // shortcut for referential equality
}
if (other == null) {
return false; // by definition, 'this' object is not null
}
if (!(other instanceof Pair)) {
return false;
}
Pair otherPair = (Pair) other; // Cast to the known type
// check equality of the members
if (this.table == null) {
if (otherPair.table != null) {
return false;
}
} else if (!this.table.equals(otherPair.table)) {
return false;
}
if (this.col == null) {
if (otherPair.col != null) {
return false;
}
} else if (!this.col.equals(otherPair.col)) {
return false;
}
return true;
}
HashCode follows suite. You should understand and follow the general contract of Hashcode.
@Override
public int hashCode() {
int hash = this.table==null?0:table.hashCode();
hash += 41 * this.col==null?0:col.hashCode();
return hash;
}
Upvotes: 5
Reputation: 47607
This is due to the fact that you did not override the equals and hashCode methods in the class Pair, or at least they are not properly overriden. When you invoke 'get' on a hashtable, the hashtable will first invoke the hashCode method to find the entry in its table. If hashCode is not properly overridden, then the hashtable will not find your entry. Secondly, when hashtable has found the entry, it will test that the key of the entry is equals to the one you provided (in case of hashCode clash). you can override those methods like this:
public int hashCode {
return table.hashCode()+tableName.hashCode();
}
public boolean equals(Object o) {
if (o==this)
return true;
if (o instanceof Pair) {
Pair p = (Pair) o;
return this.table.equals(p.table) && this.tableName.equals(p.tableName);
}
return false;
}
Finally, when you iterate over a Hashtable (and more generally, over a Map), you should not invoke the keys and the do a get(key) but instead, you should iterate directly over the Entries
for(Entry<K,V> e: map.entrySet()) {
System.err.println(e.getKey+" is mapped to "+e.getValue());
}
It is much more efficient because this will not invoke the hashCode and equals methods (as explained above) which can be costly operations.
Upvotes: 2