I found this program in my text book, which basically counts the occurence of each string in the String array tst.
public class Test {
private static HashMap<String, Integer> mp = new HashMap<String, Integer>();
public static void main(String[] args) { String[] tst = new String[] { "ABC", "DEF", "DEF", "DEF","ABC", "DEF", "ABC" }; checkMap(tst);
}
public static void checkMap(String[] str) { for (String st : str) { if (!mp.containsKey(st)) { mp.put(st, 1); } else { Integer ct = mp.get(st); if(ct!=null) { ct++; mp.put(st, ct); } } } for (Map.Entry<String, Integer> entry : mp.entrySet()) { System.out.println(entry.getKey() + " ocurrs " + entry.getValue()+ " times"); }
}}
The output for the code is -
ABC ocurrs 3 times
DEF ocurrs 4 timesMy question is in the if/else statement here -
if (!mp.containsKey(st)) { mp.put(st, 1); } else { Integer ct = mp.get(st); if(ct!=null) { ct++; mp.put(st, ct); } }When we haven't put any entries inside the hashmap (the hashmap is empty), on what basis does this work? Apologies if this is a very basic question, but I found no answer anywhere online that explains this. I am confused with what is written in the if/else loop. Also, this line here -
Integer ct = mp.get(st);How can we get the value to which the key is mapped when infact the hashmap is actually empty? I am trying to relate this to an array - If you query elements of an array once its created, but not initialized, it throws a null pointer. Someone, please explain how this works for a hashmap. Once again, apologies for asking such a basic question.
5 Answers
Well, in this line you check whether the map contains a key
if (!mp.containsKey(st)) {Since there is a ! before the expression, this means "if the map does not contain a key". After that, "then" block follows where you insert a key in the map with value 1 (since it does not exist).
Otherwise if the key does exist (the else block), you take the value for that key, increment it (ct++) and add it again to the map for the same key.
Let me just say that the null check (if(ct!=null)) is not necessary for this code.
General remark on this question:
How can we get the value to which the key is mapped when infact the hashmap is actually empty?
If you try to get something from the HashMap for a key that is not present in the map, the map returns null. That is true for any key you try to get from an empty map.
Can you please explain what this means though -
Integer ct = mp.get(st);
map.get(key) returns a value that is stored for that key. The map itself is a collection of key-value pairs, which means: for each key there is one value in the map. So to get the value stored for that key you invoke map.get(key). If you store map.put("ABC", 10) the map will return 10 for map.get("ABC").
- This is because of containsKey function checks if the hashMap contains particular key.
- If the HashMap is mpty and you try to do a get on non existant key you will get a null value
st is get here by the for (String st : str) loop. It has nothing to do with the HashMap.
if (!mp.containsKey(st)) {This tests if the HashMap does not contain the key st. If there are no items it obviously can not contain the key. Then in the else block it uses mp.get(st), which will now always succeed because it has been checked that mp contains st (actually, it does not not contain it).
The null check if (ct == null) is here because if for some reason the map contained null for the key in question. That however shouldn't be possible if the code only puts integers to the map and tests for the existence of the key, so the null check coulb be removed.
The test:
if (!mp.containsKey(st))tests if there is no entry in the map by that key.
It is therefore logical that in the else branch, the entry exists and has a non null value... Which makes the ct == null test redundant.
And when the value exists, the code get()s the existing value, adds 1 to it (in fact it creates a new Integer but that's another story) and put()s back the new value.
Note that that code mixes autoboxing and non autoboxing. mp.put(st, 1) does autoboxing; behind the scenes it really does mp.put(st, new Integer(1)).
Similarly:
Integer ct = mp.get(st);
ct++;is really:
Integer ct = mp.get(st);
Integer tmp = new Integer(ct.intValue() + 1);
ct = tmp; The null check is not necessary. Either the key is contained in the map and its value is not null, or it is not contained in the map.
The reason we can be confident about the value never being null is that the map (and all its contents) is defined and used in the method, and there's no opportunity for a null to get it there.
Although the get() method will return null if passed a key that it doesn't contain, that will never happen with this code.
Anyway, the code is inelegant: All those lines can be expressed as one simple line:
mp.put(mp.containsKey(st) ? mp.get(st) + 1 : 1);