problem getting value from HashMap - java

Hi all I'm using a HashMap to hold one of my object with a string key. when I put an object with a key it has no problem, when I put my second object I got my object added but can't get it with its key. Somewhat it goes to somewhere that is "next". I took a screenshot from debug mode (eclipse), below
although size shows 2, I can't see my second item in hashmap, but in other hashmap's next node.
To note something I use my key like in a form "name.tag", tag and name in same time can never be the same, but "tag" can be the same. does hashmap has something to do with dot operator when evaluating keys? I hope I could write clearly,
Thanks in advance
Edit:
Here is a piece of code I use to create my hashmap
private HashMap<String,ParameterItem> parseParametersNode(DataModel parent,Element element){
NodeList parameterChilds=element.getChildNodes();//gep element parameters
HashMap<String, ParameterItem> parameterItems=new HashMap<String, ParameterItem>();
for(int i=0;i<parameterChilds.getLength();i++){
if(parameterChilds.item(i).getNodeType()==Node.ELEMENT_NODE){
Element el=(Element) parameterChilds.item(i);
NamedNodeMap atts=el.getAttributes();
ParameterItem item=new ParameterItem();
for(int j=0;j<atts.getLength();j++){
Attr attribute=(Attr) atts.item(j);
String attributeValue=attribute.getValue();
String attributeName=attribute.getName();
item.setParsedProperty(attributeName, attributeValue);
} /*check attributes later*/
//finish loop and insert paramitem to params
String key="key"+i;
if(item.getTag()!=null && item.getName()!=null)
key=item.getName()+"."+item.getTag();
parameterItems.put(key, item);
// testParam=item;
// parameterItems.put(key, testParam);
}
}
return parameterItems;
}

There is not really a problem here: you have a hash collision. That is, both of your keys have been placed in the same hash bucket. It appears you have only four buckets (odd, I thought the initial default was 10 or 16), so the chance of that with random data is 25 percent. Your size incremented just fine. The next is the internal implementation’s way of pointing to the next element in the same bucket. If the number of elements in each buckets gets too big, Java will internally rehash into more buckets.
I do not see why you need a HashTable here since you are numbering your keys consecutively (you could use an ArrayList), but maybe this is just starter code and your real use case is different.

You have the code:
String key="key"+i;
but right after this you set key again not adding to it:
if(item.getTag()!=null && item.getName()!=null)
key=item.getName()+"."+item.getTag();
Should this be key +=item.getName()+"."+item.getTag(); ?

Related

Checking the existence of the key before adding a newhashmap

I would like to check if the key already exists before adding an item to the Hashmap. Adds keys from 1 to 20k to the Hashmap, and some may repeat themselves. I would like to check if the key I want to add already exists, if so, I write it to the screen, for example.
I know that you can check if such a key exists with the containsKey method, but I have no idea how to refer to the previous element.
I have absolutely no idea how to start this because I'm just getting started with beanshell :/
Thanks in advance for your help :D
Map MAP_SA = new HashMap()
while(iterator.hasNext()){
org = iterator.next();
MAP_SA.put(org.getExtended(),org.getName());
//here I would like to check if the key repeats before adding anything to the map
}
You can also use the putIfAbsent method on Map interface (available as from JDK 8) which, as the name indicates it, will only add the value only if the specified key does not exist yet.
Assumption:
Keys in Maps are unique, so if you try to insert a new record with a key already present, there will be a "collision" and the value corresponding to that key in the map will be overwritten.
Answering your question:
containsKey() is the correct way, especially in your case where you do a check at runtime, you have the possibility to check at each iteration if the current value you want to insert is already present in the whole map, because containsKey() goes to probe all the keys in the map.
Map MAP_SA = new HashMap()
while(iterator.hasNext()){
org = iterator.next();
if(!MAP_SA.containsKey(org.getExtended8())){ // check all over the map
MAP_SA.put(org.getExtended8(),org.getName());
}else
System.out.println("Error: the key already exists");
}

Hashmap with two key object having same value but different bucket index

If Hashmap has two keys having same value, for eg:
HashMap map=new HashMap();
map.put("a","abc");
map.put("a","xyz");
So here put two key with "a" value and suppose for first bucketindex=1 and
second bucketindex=9
So my question is if bucket index for both is coming different after
applying hashing algorithm, in this how to handle for not inserting
duplicate key as it is already present and hashmap cannot have duplicate
key.
please suggest your view on this.
There won't be any such thing as "second bucket index".
I suggest you add something like System.out.println(map.toString()) in order to see what that second put() has done to your map.
EDIT:
In the method put(key,value), the "bucket index" is computed as a function of the key element's value, not the value element's value (so "a" and "a" give the same index for the bucket). This function is supposed to be deterministic so feeding it the same value ("a" in your case), the same hashCode() will come out and subsequently, the same bucket index.
In Java if a hashing function returns the same hash, equality of two objects is determined by equals() method. And if the objects are found equal, the old one is simply replaced by the new one.
Instead, if the objects are not equal, they just get chained in a linked list (or a balanced tree) and the map contains both objects, because they are different.
So, back to your question: "if bucket index for both is coming different after applying hashing algorithm" - this is impossible for equal objects. Equal objects must have the same hash code.
To make #Erwin's answer more clear, here's the source code of HashMap from JDK
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
Digging more deep you will find that the bucket index is calculated from key's hash code.
To make it simple and straightforward, putting duplicate key with different values to the same HashMap will result just one single entry, which the second put is just overwriting the value of the entry.
If your question is how to create a hashmap that can handle more than one value for the same key, what you need is a Map> so it adds a new value to the arraylist everytime the key is the same.

Iterating over a key set of a LinkedHashMap

is it possible to retrieve the next (next, as in the next key value which has been inserted) key value of a LinkedHashMap?
E.g. the current key value is 2 and the next key value is 4. I want to use the value of the next key without setting my iterator (or whatsoever) one index further. Apparently using one iterator doesn't seem to do the job. Another idea would be to cast the set returned by myHashMap.keySet() to some other implementing class but I am not sure if it is possible to retrieve the next element.
Any ideas?
Assume there is LinkedHashMap<K,V> linkHashMap, now define a custom method getNextKey which takes a parameter index and return the next index value if valid.
Code snippet (not working code)-
public K getNextKey(int index){
// put check if index is valid
K[] keyArray = linkedHasMap.keySet.toArray(new K[linkedHasMap.size()]);
return K[index+1];
}

remove element from hash map if key is empty

how can I find an element of an HashMap in Java, if the HashMap is of the form and one key is empty, so it only contains a blank character.
In my example:
Let wordMap be an instance of HashMap filled with elements.
if (wordMap.containsKey("")) {
wordMap.remove("");
}
This didn´t work. I hope someone can help me.
After I did this, I convert the hash map to a tree map and sort it by the biggest Integer. I print that to the console and this is what I get with
System.out.println("results: " + tree)
I get on the console:
results: { =194, in=73, ...}
Thanks
You can do a couple of different things. For your issue, I would do:
if (wordMap.containsKey(" ")) {
wordMap.remove(" ");
}
However, to be more comprehensive I would iterate over the keys and remove any key that passes the StringUtils.isEmpty() test.
Are you trying to retrieve the value? If yes, then you need replace that
wordMap.remove("");
with
wordMap.get("");
Otherwise, if you're trying to remove the Entry with a key "" that is the correct way to do it.
If you are using Java 8,
then you can apply the following solution.
wordMap.entrySet()
.removeIf(e -> StringUtils.isBlank(e.getKey()));
Here StringUtils.isBlank can be replaced with custom logic to check for invalid keys.

java why does an enhanced for loop iterate over null results in a HashMap with more than 16 or more items?

The code I used originally, which returned a NullPointerException in some places for any HashMap containing 16 or more elements:
for(Entry<Integer, String> e : myHashMap.entrySet()){
System.out.println(e.getKey() + ": "+e.getValue());
}
The code I am now using, which works on the same HashMap, regardless of size:
int i = 0; //variable to show the index
int c = 0; //variable to count the number items found
while(c < myHashMap.size()){
if(myHashMap.containsKey(i)){ //if the HashMap contains the key i
System.out.println(i + ": "+myHashMap.get(i)); //Print found item
c++; //increment up to count the number of objects found
}
i++; //increment to iterate to the next key
}
What is the difference between the two? Why does the first one iterate over null values? And, more importantly, why does the first one iterate out of order if there are 16 or more items? (ie: 12,13,17,15,16,19,18 instead of the neat 12,13,14,15,16,17,18,19 in the second)
I think I am just starting to scratch the surface of java, so I would like to understand why it was designed this way. Any book recommendations on this kind of thing are welcome.
You should read the documentation of a class and try to understand its purpose before starting to use it. HashMap provides an efficient storage but no guaranteed order. It’s just a coincident that you didn't discover it with smaller HashMap sizes because the default capacity is 16 and the hash codes of contiguous Integer objects are contiguous too. But that is not a property you can rely on. You always have to assume no guaranteed order for a HashMap.
If you need the insertion order you can use a LinkedHashMap, if you need ascending order of the keys you can use a TreeMap. If you have a contiguous range of Integer keys and want ascending order you can simply use an array as well.
The foreach loop for(Entry<Integer, String> e : myHashMap.entrySet()) does not “iterate over null values”. It iterates over the values contained in the HashMap which are the values you have added before. There can be at most one null key contained in the map, if you added it. You might see null values in the debugger when looking at the internal array of a HashMap which are unused slots as a HashMap has a capacity which can be larger than its size.

Categories