This question already has answers here:
Why does ConcurrentHashMap prevent null keys and values?
(7 answers)
Closed 9 years ago.
Most of the synchronized and concurrent collections like HashTable, ConcurrentHashMap etc do not allow null values. Is there any specific issue with null elements?
Hashtable is somewhat obsolete so I won't comment on it. As for ConcurrentHashMap one of the important additions of the API vs. a standard HashMap are a few atomic methods such as putIfAbsent. Javadoc:
Returns the previous value associated with the specified key, or null if there was no mapping for the key
In particular, if the map allowed null keys, the method would be a lot more complicated to use. A typical pattern, where you need to make sure that values can't be overwritten, is:
ConcurrentMap<K,V> map = new ConcurrentHashMap<> ();
V value = map.get(key);
if (value == null) {
value = new V();
V previousValue = map.putIfAbsent(key, value);
if (previousValue != null) { //Here you need to be sure what that means
value = previousValue;
}
}
useValue(value);
Another example is how you check if a key is in a HashMap (and you need the return value):
V value = map.get(key);
if (value == null && !map.containsKey(key)) {
}
The problem in a concurrent environment is that the whole thing is not atomic.
See also this post and these comments by the author of CHM.
HashTable.get(key) method returns null if the specified key is not present in the HashTable. If HashTable allows null as values, there can be two possibilities if I am getting a null from HashTable.get(key) method.
The key is not present in HashTable
The key is present, but the value set was null
It may be confusing for the user of the API.
I believe they don't allow null values just to prevent this ambiguity.
This is a synchronized map that accepts null key and values
Map m = Collections.synchronizedMap(new HashMap());
From the Hashtable JavaDoc:
To successfully store and retrieve objects from a hashtable, the
objects used as keys must implement the hashCode method and the
equals method.
In a nutshell, since null isn't an object, you can't call .equals() or
.hashCode() on it, so the Hashtable can't compute a hash to use it as
a key.
HashMap is newer, and has more advanced capabilities, which are
basically just an improvement on the Hashtable functionality. As such,
when HashMap was created, it was specifically designed to handle null
values as keys and handles them as a special case.
Specifically, the use of null as a key is handled like this when
issuing a .get(key):
(key==null ? k==null : key.equals(k))
Source:Why does Hashtable not take null key?
When you synchronize it means you will obtain lock on that object or at some portion. If your object is null then how will you decide that in which portion you will obtain lock?
Say in concurrenthashmaps, you can divide it into 16 different locks. Now how will you decide where null will be placed?
Null has no value attached to it, it simply means no object. So to avoid ambiguity its better not to have it.
Related
I'm trying to work with Java's Junit Test. My goal is to create a hashtable as
Hashtable< String , Hashtable<String,String> > student =
new Hashtable<String, Hashtable<String, String>>();
Next, I want to add at first only the key. After that, when I have the value then add it to the key in hashtable.
Example
student.put("student1",null) ;
I tried to work with null, but during test process I get a
java.lang.NullPointerException
Is it not possible? Any ideas to how adding only the key without value?
Is it possible to add a key without a value in hashtable Java?
Short answer: No
Why?
Because it will throw and Exception if
* #exception NullPointerException if the key or value is
* <code>null</code>
And in the same source code has a validation
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}
...
You can use a Map Instead.
HashTable is an older implementation and HashMap came as an advanced version with more capabilities. You can't call .equals() or .hashCode() on it as null isn't an object.
HashMap is a better replacement for single threaded applications or any time synchronization is not a requirement, because of the performance impact synchronization introduces. If you need a Threadsafe option you can also use ConcurrentHashMap
The documentation says that you can't:
Maps the specified key to the specified value in this hashtable.
Neither the key nor the value can be null.
The best that you can do, if you need the key, is to use an empty HashTable as the value:
student.put("student1", new Hashtable<>());
In most use cases you would not care about putting null into a HashMap. You can check which keys have a value assigned via the keySet() and treat everything else as null (since it was never assigned).
However, your question to me indicates that you need to distinguish three states: Key-Value pair, key that were never assigned a value, and keys that were explicitly assigned a null value.
Since the default HashMap does not support this behavior, you could implement your own class that implements the Map interface. It basically only wraps a HashMap, with a few important exceptions:
When you assign a value of null to a key, you put the key into a Set of "NullKeys" instead of into the HashMap.
When you retrieve a key, check whether it is in the "NullKey" Set. If yes, return null, otherwise look into the HashMap.
There are some special cases (overwriting an existing value with null etc.) but this would be the basic strategy.
(I am not sure whether this is a useful class to have other than in very specialized scenarios but it would meet your requirements.)
This question already has answers here:
Why Hashtable does not allow null keys or values?
(10 answers)
Closed 4 years ago.
I know about null key is not allowed in Hashtable because to store element in Hashtable hash code must required. But if key is null it will unable to calculate hash code for null key. But I don't understand but what is the exact reason in mind for Sun developers not to allow null value.
Someone says there is null check for value inside put method implementation and that's why it throws NullPointerException. But my question is why that null value check. Is there any specific reason behind it.
I went through lots of read but no got satisfied answer. Some one says there is ambiguity if there is null value and if you try to retrieve value using get() method it will return null and this null is because of actual value is null or key is missing that's why null and could not predict reason. So i need pin point answer with proof.
You will get NULL for value if you do
hashtable.get("key")
and "key" is not in the map, then you don't need to store null values.
If you would be able to store null, you will never know what you had: null mapping or that is a missing mapping.
Hashtable is considered legacy code. You should use HashMap and it allow null for values and also one key can be null.
EDIT
After deeper search I may have argument for such decision. Hashtable is synchronized (and HashMap isn't).
From JavaDoc:
Unlike the new collection implementations, Hashtable is synchronized. If a thread-safe implementation is not needed, it is recommended to use HashMap in place of Hashtable. If a thread-safe highly-concurrent implementation is desired, then it is recommended to use ConcurrentHashMap in place of Hashtable.
As you can see successor of Hashtable is not HashMap as I previously write but ConcurrentHashMap. I was surprised that ConcurrentHashMap does not allows null. I start digging and found this:
From the author of ConcurrentHashMap himself (Doug Lea):
The main reason that nulls aren't allowed in ConcurrentMaps (ConcurrentHashMaps, ConcurrentSkipListMaps) is that ambiguities that may be just barely tolerable in non-concurrent maps can't be accommodated. The main one is that if map.get(key) returns null, you can't detect whether the key explicitly maps to null vs the key isn't mapped. In a non-concurrent map, you can check this via map.contains(key), but in a concurrent one, the map might have changed between calls.
So maybe authors of Hashtable have the same reason as authors of ConcurrentHashMap
Having a null value is still considered a bad decision in HashMap and the new Map classes and the static factory methods in java-9 prove that:
Map.of("test", null)
will throw a NulPointerException
From Java Documentation
To successfully store and retrieve objects from a hash table, the
objects used as keys must implement the hashCode method and the equals
method
Null is not an object, so can not call .equals() or .hashCode() on it, so the Hashtable can't compute a hash to use it as a key
Hashtable containsValue(Object value) function throw NullPointerException if the value is null so for the value also not allowed null
This question already has answers here:
Why is it useful to have null values or null keys in hash maps?
(6 answers)
Closed 5 years ago.
why HashMap contains single null value in java ?
I have asked in an Interview why HashMap allows Null Value. I found an article it describing the implementation of HashMap. but doesn't show why it only contains null. what is reason behind that, why Designer design to contains Null.
From Oracle Source...
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
Hash table based implementation of the Map interface. This implementation provides all of the optional map operations, and permits null values and the null key. (The HashMap class is roughly equivalent to Hashtable
http://docs.oracle.com/javase/6/docs/api/java/util/HashMap.html
but why HashMap allows only single Null value ?
We can speculated that HashMap allows null keys and null values because it is useful to do so. Or, from the other side, it would not bring much added value to forbid nulls.
HashMap allows for just one null key because Maps in general do not support duplicate keys.
Hashtable (the predecessor of HashMap) didn't allow null which was a pita in cases where you needed a map where you stored key-value-pairs with null as possible value because trying to set that lead to a NullPointerException.
You ended up creating a private final static Object NULL that is set as value instead and each time you set or retrieve a value you had to check for null/the representative value and change it accordingly.
HashMap allowing null as value was highly appreciated because of this.
Why in Java one null key is allowed in Hashmap, while in case of Hashtable it is not allowed ?
http://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html
If you look at docs of HashMap
The HashMap class is roughly equivalent to HashTable, except that it is unsynchronized and permits null's.)
HashTable is the older version of HashMap which failed in that case of handling null's. And HashMap got that feature added into it to get more advanced than HashTable.
HashMap allows the null key. If you try to insert the another value of same key, it will override it.
Incase of HashTable, put(K key, V value) throws the Null pointer Exception if the key or value is null.
Refer the source code.
HashMap: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/util/HashMap.java#HashMap.put%28java.lang.Object%2Cjava.lang.Object%29
HashTable: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/Hashtable.java#Hashtable.put%28java.lang.Object%2Cjava.lang.Object%29
Hash table is very old class , from JDK 1.0
To understand this, first of all you need to understand comments written on this class by author.
This class implements a hashtable, which maps keys to values. Any non-null object can be used as a key or as a value. To successfully store and retrieve objects from a hashtable, the objects used as keys must implement the hashCode method and the equals method.
HashTable class is implemented on hashing mechanism, that’s mean to store any key-value pair, its required hash code of key object. If key would be null, it will not able to given hash ,it will through null pointer exception and similar case for value it is throwing null if the value is null.
But later on it was realized that null key and value has its own importance that is why one null key and multiple null values are allowed in later implemented classes like HashMap class.
For hash map null keys will allow and there is a null check is there for keys if the key is null then that element will be stored in a zero location in Entry array. null key we can use for some default value..
Lets say I have a concurrenthashmap with some keys and values that are not null. Later these keys can become null, then what happens? Are they automatically removed from concurrenthashmap or do they stay there as null? Does the size() method count them?
Most Java Maps can contain null values.
The following code is perfectly valid and will return a size of 1.
Map m = new HashMap<String, String>();
m.put("foo", null);
System.out.println(m.size()); //will print "1"
This is because HashMap allows for null values.
Turns out, however, based on my testing, that the following code will NOT work.
Map m = new ConcurrentHashMap<String, String>();
m.put("foo", null); //Will throw a NullPointerException
This is because, apparently, ConcurrentHashMap does not allow for null values.
According to the Javadoc(http://docs.oracle.com/javase/7/docs/api/java/util/Map.html):
Some map implementations have restrictions on the keys and values they may contain. For example, some implementations prohibit null keys and values, and some have restrictions on the types of their keys.
So, there you have it. Hope this helps :)
From ConcurrentHashMap API:
Like Hashtable but unlike HashMap, this class does not allow null to be used as a key or value.