Consider the following code:
Map<Integer, Material> TestMap= new HashMap<Integer, Material>();
if (TestMap.get(index)!= null) {
index++;
}
What will happen if TestMap.get(index) is null? Some say it will exit the code, some say it will throw ArrayIndexOutOfBoundsException.
Your code won't throw an ArrayIndexOutOfBoundsException, for it's a HashMap. As per the documentation of the get() method of HashMap:
public V get(Object key)
Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
So if the HashMap does not contain a value for ìndex, if will return null, no problem there.
EDIT
If your HashMap was a List, and you added 10 elements, and you called get(25) on the List, then you'd get an ArrayIndexOutOfBoundsException.
So to summarize
if (TestMap.get(index)!= null) {
index++;
}
This piece of code doesn't throw any Exceptions (except when TestMap is null). If there's no value for the given key, get() returns null, and since you perform a null check, the if is not entered when the key doesnt exist in the map.
Related
How can I check that an element has been properly removed from a Map in java?
Given:
ConcurrentHashMap<Integer,Object> myMap = new ConcurrentHashMap<>();
myMap.put(1, new Object());
myMap.remove(1);
Is the below code the only way to check it?
myMap.contains(1);
remove() returns the removed object, or null if it is not present in the map:
Returns:
the previous value associated with key, or null if there was no mapping for key.
Object removedObject = myMap.remove(1);
boolean wasRemoved = removedObject != null;
In fact by using, contains(), the object might have been removed by another thread between the calls to remove() and contains(), if the map is shared between threads. That your question uses a ConcurrentHashMap hints that concurrency might be a case here.
In a recent interview, question I faced was
How can you handle null pointer when iterator encounters a null key
while iteration over a hashmap. assume my developer has inserted a
null key by mistake
My answer was: Just we need to check null!=entry.getKey().
he was not satisfied and said before that how will you handle.
How should I answer that question. When I was back.
I tried this
public class Main {
public static void main(String[] args) {
Map<String,String> map = new HashMap<String,String>();
map.put(null, "null");
map.put("null",null);
map.put("test", "test");
Iterator<Entry<String, String>> it = map.entrySet().iterator();
while(it.hasNext()){
System.out.println(it.next().getKey());
}
}
}
output:
null
test
null
there is no exception. What was he trying to ask actually. or is that I am missing some concepts? Please guide me
map.remove(null)
From JavaDocs:
Returns the value to which this map previously associated the key, or null if the map contained no mapping for the key.
If this map permits null values, then a return value of null does not necessarily indicate that the map contained no mapping for the key; it's also possible that the map explicitly mapped the key to null.
The map will not contain a mapping for the specified key once the call returns.
Call it before iteration, and it will remove explicit null keys
I guess the key point that he want to test by this question is What happend when called the method next() on the object Iterator.
He maybe want to know whether or not you will programming like the following way when you want to iterate a map:
Map map = new HashMap();
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
if (null != iter.next().key()) {
System.out.println(iter.next());
}
}
If you programming like above example, the next method will called twice, and you will not get the correct object that you really want to check. Instead, you should write code like this:
Map map = new HashMap();
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
// Key point: define a refreence point to the object returned by the
// method `next()`
Entry entry = iter.next();
if (null != entry.key()) {
System.out.println(entry);
}
}
I was going through the add method of HashSet. It is mentioned that
If this set already contains the element, the call leaves the set unchanged and returns false.
But the add method is internally saving the values in HashMap
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
The put method of HashMap states that
Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the old value is replaced.
So if the put method of HashMap replaces the old value, how the HashSet add method leaves the set unchanged in case of duplicate elements?
PRESENT is just a dummy value -- the set doesn't really care what it is. What the set does care about is the map's keys. So the logic goes like this:
Set.add(a):
map.put(a, PRESENT) // so far, this is just what you said
the key "a" is in the map, so...
keep the "a" key, but map its value to the PRESENT we just passed in
also, return the old value (which we'll call OLD)
look at the return value: it's OLD, != null. So return false.
Now, the fact that OLD == PRESENT doesn't matter -- and note that Map.put doesn't change the key, just the value mapped to that key. Since the map's keys are what the Set really cares about, the Set is unchanged.
In fact, there has been some change to the underlying structures of the Set -- it replaced a mapping of (a, OLD) with (a, PRESENT). But that's not observable from outside the Set's implementation. (And as it happens, that change isn't even a real change, since OLD == PRESENT).
The answer that you may be looking comes down to the fact that the backing hashmap maps the elements of the set to the value PRESENT which is defined in HashSet.java as follows:
private static final Object PRESENT = new Object();
In the source code for HashMap.put we have:
386 public V put(K key, V value) {
387 if (key == null)
388 return putForNullKey(value);
389 int hash = hash(key.hashCode());
390 int i = indexFor(hash, table.length);
391 for (Entry<K,V> e = table[i]; e != null; e = e.next) {
392 Object k;
393 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
394 V oldValue = e.value;
395 e.value = value;
396 e.recordAccess(this);
397 return oldValue;
398 }
399 }
400
401 modCount++;
402 addEntry(hash, key, value, i);
403 return null;
404 }
Because the key in question already exists, we will take the early return on line 397. But you might think a change is being made to the map on line 395, in which it appears that we are changing the value of a map entry. However, the value of value is PRESENT. But because PRESENT is static and final, so there is only one such instance; and so the assignment e.value = value actually doesn't change the map, and therefore the set, at all!
Update:
Once a HashSet is initialized.
- All the items in it are stored as keys in a HashMap
- All the values that HashMap have ONLY ONE object that is PRESENT which is a static field in HashSet
As you can see the HashSet.add method adds the element to the HashMap.put as a key not as a value. Value is replaced in the HashMap not the key.
See HashMap#put:
Associates the specified value with the specified key in this map. If
the map previously contained a mapping for the key, the old value is
replaced.
It replaces the key with the new value, this way, no duplicates will be in the HashSet.
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
e is the key, So if e is already present put will not return null. Hence add will return false.
JavaDoc for put :
the previous value associated with key, or null if there was no mapping for key. (A null return can also indicate that the map previously associated null with key.)
From javadocs for HashMap.put(),
"Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the old value is replaced."
Thus the map value will be replaced, (which is a constant static field in HashSet class, and thus the same instance is replaced), and the map key is kept untouched (which, in fact IS the Set collection item)
I have two Hashmaps
HashMap<Integer, Integer> inventoryRequirements = new HashMap<Integer, Integer>();
HashMap<Integer, Integer> inventory = new HashMap<Integer, Integer>();
I have a loop that checks current and adds to it:
for(Item item : items){
int currentRequirement = 0;
currentRequirement = inventoryRequirements.get(item.get_id());
inventoryRequirements.put(item.get_id(), currentRequirement++);
}
I have another loop that checks inventory and adds to it:
for(Item item : items){
int currentInventory = 0;
// this next line returns null
currentInventory = inventory.get(item.get_id());
inventory.put(item.get_id(), currentInventory++);
}
The first one works fine, but the second one pukes and returns a null. I don't understand why the second one does not work. Both are initially in the same state as depicted in the code sample.
EDIT
The two HM get populated as you see here - really! I know it may be hard to believe but the first one works and the second one does not.
Both of the loops you show will throw a NullPointerException (NPE) if the key you request via get() is not in the Map.
Map.get() returns null when the key is not present (or of course if the value stored with that key is null). An Integer (autoboxed type) that is null can not be autounboxed into an int so it throws an NPE.
The safe way of performing this is:
for (Item item : items) {
Integer currentRequirement = inventoryRequirements.get(item.get_id());
if (currentRequirement != null) {
inventoryRequirements.put(item.get_id(), currentRequirement++);
}
}
Of course, it's also completely possible that you have an Item in your collection that is null and that is what is throwing the NPE.
If the code you have provided is complete, then you haven't put anything in your hashmap.
So it will always return null.
You are getting a item from inventory but it's empty
The best practice is to write the code in the following manner:
for(Item item : items){
int currentRequirement = 0;
currentRequirement = inventoryRequirements.get(item.get_id());
if(currentRequirement!=null){
//update currentRequirement only if it exists in the map.
inventoryRequirements.put(item.get_id(), currentRequirement++);
} else {
//add it to the map otherwise.
inventoryRequirements.put(item.get_id(), 1);
}
Ugg. Also, when all else fails, don't overlook the possibility that it is not returning null because its not finding the key. It could be returning null because when the key/value pair was added... the value added was null. Just spent more time than I care to admit tracking this down.
So, to recap, there are at least two reasons the HashMap could be returning null:
It's not finding the key
It is finding the key, but the value inserted for the key is null
Doh!
I was just reading about the difference between HashMap and HashTable class in java. There I found a difference that former allow null key and later doesn't privileges for the same.
As far as the working of HashMap is concern I know that, it calls hashcode method on key for finding the bucket in which that key value pair is to be placed. Here comes my question:
How hashcode for a null value is computed or Is there any default value for hashcode of null key (if so please specify the value)?
from HashMap:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
...
and if you look further you will see that null always goes to bin 0
From the source code of HashMap, if the key is null it is handled differently. There is no hashcode generated for null, but it is uniquely stored at index 0 in an internal array with hash value 0. Also note that hash value of an empty string also is 0(in case keys are strings), but the index where it is stored in the internal array ensures that they are not mixed up.
/**
* Offloaded version of put for null keys
*/
private V putForNullKey(V value) {
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(0, null, value, 0);
return null;
}
If you read description of static int hash(int h) method in HashMap you will find that null keys have index 0.
When a null value is existing in the map the key of that value is also null. you can not have many null keys in a map. Only one null key.
It clearly states what happens when you do a put with a key which was already in the map. The specific case of key == null behaves in the same way: you can't have two different mappings for the null key (just like you can't for any other key). It's not a special case, for the context of your question.
Internally Hashmap have a nullcheck for key. If it is null then it will return 0 else hash value of key.
where as Hastable doesn't have any null check and it will call directly hashcode method on key
that's why Hashtable won't accepts null.