Today i read in a book:-
"HashMap allows one null key and multiple null values in a collection."
HashMap<Object,Object> ih=new HashMap<Object,Object>();
Object o1=null;
Integer o2=null;
ih.put(o1,null);
ih.put(new Integer(2),null);
ih.put(o2,new Integer(3));
This example is putting two null object references in the map.
But the following Example is successfully compiling and running...
I cant figure out why?
"HashMap allows one null key and multiple null values in a
collection."
Allow one null key means if you keep adding null key, it will overwrite the previous values. Actually, this is true for any key in HashMap.
The bottom line is - HashMap allows only one key
e.g. if you print the size of your Hashmap it will be 2.
System.out.println("size:: "+ih.size());
What the book probably means is this:
among the possible keys of a HashMap<X, Y>, there can be a null key;
whatever the key (even null!), the value associated to this key can be null.
Therefore, it is perfectly normal that your code works. It is just that the book's text here is quite confusing.
But of course, this entirely depends on the Map implementation; some of them, such as ConcurrentHashMap, will not allow null keys or values.
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.)
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..
In a HashMap we know when we store the key and value , actually a Map.entry object is populated where Map.entry.key is mapped to key inserted in hashMap and Map.entry.value is mapped to value inserted in hashmap . Now my question is how is the supplied key is related to supplied value in a hashmap .
I mean if my understanding is correct key is not referencing directly to the value of hashMap and hence even if this reference is made to null , it should not impact the value in hashmap getting garbage collected.
Your understanding is not correct. A key-value pair is stored as an object of a class called Map.Entry. A null key is also valid key in a HashMap, and its Hashvalue equals 0. If you specify a key as null it will store as a unique key-value pair and any more entries with null key will override the previous entry. The object inside Map.Entry.key maybe null , but it itself is being stored in an LinkedList(Bucket of Entries) of hashMap and hence will not be Garbage Collected. To remove a Object from HashMap call the .remove(key) method instead of nullifying keys and depending on GC
You understanding may be right. I suggest you to read the source code from JDK.
Actually, Hashmap or other hash collections often use a array . In java
Entry<K,V>[] table
the keys hashcode() % tableSize (just for understanding) determine which index the key stores in the table array.
I want to maintain a list of objects such that each object in the list is unique.Also I want to retrieve it at one point. Objects are in thousands and I can't modify their source to add a unique id. Also hascodes are unreliable.
My approach was to utilize the key uniqueness of a map.
Say a maintain a map like :
HashMap<Object,int> uniqueObjectMap.
I will add object to map with as a key and set a random int as value. But how does java determine if the object is unique when used as a key ?
Say,
List listOne;
List listTwo;
Object o = new Object;
listOne.add(o);
listTwo.add(o);
uniqueObjectMap.put(listOne.get(0),randomInt()); // -- > line 1
uniqueObjectMap.put(listTw0.get(0),randomInt()); // --> line 2
Will line 2 give an unique key violation error since both are referring to the same object o ?
Edit
So if will unqiueObjectMap.containsKey(listTwo.get(0)) return true ? How are objects determined to be equal here ? Is a field by field comparison done ? Can I rely on this to make sure only one copy of ANY type of object is maintained in the map as key ?
Will line 2 give an unique key violation error since both are referring to the same object o ?
- No. If a key is found to be already present, then its value will be overwritten with the new one.
Next, HashMap has a separate hash() method which Applies a supplemental hash function to a given hashCode (of key objects), which defends against poor quality hash functions.
It does so by calling the Object's hashcode() function.
The default implementation is roughly equivalent to the object's unique identifier (much like a memory address); however, there are objects that are compare-by-value. If dealing with a compare-by-value object, hashcode() will be overridden to compute a number based on the values, such that two identical values yield the same hashcode() number.
As for the collection items that are hash based, the put(...) operation is fine with putting something over the original location. In short, if two objects yeild the same hashcode() and a positive equals(...) result, then operations will assume that they are for all practical purposes the same object. Thus, put may replace the old with the new, or do nothing, as the object is considered the same.
It may not store two copies in the same "place" as it makes no sense to store two copies at the same location. Thus, sets will only contain one copy, as will map keys; however, lists will possibly contain two copies, depending on how you added the second copy.
How are objects determined to be equal here ?
By using equals and Hashcode function of Object class.
Is a field by field comparison done ?
No, if you dont implement equals and hashcode, java will compare the references of your objects.
Can I rely on this to make sure only one copy of ANY type of object is maintained in the map as key ?
No.
Using a Set is a better approch than using Map because it removes duplicates by his own, but in this case it wont work either because Set determinates duplicates the same way like a Map does it with Keys.
If you will refer to same then it ll not throw an error because when HashMap get same key then it's related value will be overwrite.
If the same key is exist in HashMap then it will be overwritten.
if you want to check if the key or value is already exist or not then you can use:
containsKey() and containsValue().
ex :
hashMap.containsKey(0);
this will return true if the key named 0 is already exist otherwise false.
By getting hashcode value using hash(key.hashCode())
HashMap has an inner class Entry with attributes
final K key;
V value;
Entry<K ,V> next;
final int hash;
Hash value is used to calculate the index in the array for storing Entry object, there might be the scenario where 2 unequal object can have same equal hash value.
Entry objects are stored in linked list form, in case of collision, all entry object with same hash value are stored in same Linkedlist but equal method will test for true equality. In this way, HashMap ensure the uniqueness of keys.
I have some questions about Java Collection objects...
When we add objects to a collection like HashSet or HashMap, how the the objects internally stored?
Why doesn't Hashtable allow null values?
You're not adding an object to the collection. You're adding a reference.
As for why HashTable doesn't allow null keys and values - it's just a design decision; in some cases it's helpful to disallow null keys, while in others it's annoying. HashMap does allow for both null keys and values, for example. There are various reasons for prohibiting nulls:
Usually a null key or a null value indicates a programming error in the calling code. Rejecting this at the point of insertion makes it far easier to find the error than waiting until the code fetches a value and then has an unexpected null.
If you know that values in a map can't be null, then you don't need to do a separate check for containment and then fetch: you can fetch, and if the result is null, you know the key was missing.
It takes a bit more work to handle null keys in the map implementation. While null values can sometimes be useful, null keys almost never are.
Hashtable does not allow null values because it uses the equals and hashcode methods of the objects added to it
http://en.wikipedia.org/wiki/Hash_function