NullPointerException when using putAll(map) to put map into properties - java

I am trying to put a map into a properties using putAll() and get a NullPointerException even when my map is not null
Map<String,Object> map = item.getProperties();
Properties props = new Properties();
if(map!=null) {
props.putAll(map); //NPE here
}
The item.getProperties() returns Map<String,Object> and I want to store those properties into a properties file.
I also tried to instantiate the map first
Map<String,Object> map = new HashMap<String, Object>()
map = item.getProperties();
Properties props = new Properties();
if(map!=null) {
props.putAll(map); //NPE here
}
I know that the map is not null, since I can see the map values in the log.

The Properties class extends Hashtable which does not accept null values for its entries.
Any non-null object can be used as a key or as a value.
If you try to put a null value, the Hashtable#put(Object, Object) method throws a NullPointerException. It's possible your
map = item.getProperties();
contains null values.

public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
V old = e.value;
e.value = value;
return old;
}
}
modCount++;
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash();
tab = table;
index = (hash & 0x7FFFFFFF) % tab.length;
}
// Creates the new entry.
Entry<K,V> e = tab[index];
tab[index] = new Entry<K,V>(hash, key, value, e);
count++;
return null;
}
Maybe your map has null key or value.

Related

When the count field of Java Hashtable initialized?

When reading the Java Hashtable source code I noticed that the count field of Hashtable is not initialized when declare I see that in the readObject method there is this code:
count = 0;
When is the count field initialized?
readObject also calls reconstitutionPut(table, key, value) for each key-value pair, and that method increments count.
Here's the relevant code with the relevant lines marked:
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException
{
...
count = 0;
// Read the number of elements and then all the key/value objects
for (; elements > 0; elements--) {
#SuppressWarnings("unchecked")
K key = (K)s.readObject();
#SuppressWarnings("unchecked")
V value = (V)s.readObject();
// synch could be eliminated for performance
reconstitutionPut(table, key, value); // <---------------
}
}
private void reconstitutionPut(Entry<?,?>[] tab, K key, V value)
throws StreamCorruptedException
{
if (value == null) {
throw new java.io.StreamCorruptedException();
}
// Makes sure the key is not already in the hashtable.
// This should not happen in deserialized version.
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
throw new java.io.StreamCorruptedException();
}
}
// Creates the new entry.
#SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++; // <---------------
}

How and when check whether key is null in a hashtable

As we know, null is not allowed in Hashtable.
But when I checked the source code of Hashtable (jdk 1.8).
I only saw the check of value and couldn't find the key check.
Here is the source code below of the put method:
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
#SuppressWarnings("unchecked")
Entry<K,V> entry = (Entry<K,V>)tab[index];
for(; entry != null ; entry = entry.next) {
if ((entry.hash == hash) && entry.key.equals(key)) {
V old = entry.value;
entry.value = value;
return old;
}
}
addEntry(hash, key, value, index);
return null;
}
The key check is here:
int hash = key.hashCode();
This will throw a NullPointerException if the key is null.

Treemap get throws NullPointerException

Follwing is my java class TestEntry.java
private void initializemapTest()
{
eventMap = new TreeMap<String,String>();
//Put some value into eventMap
mapTest = new TreeMap<String, String>( new Comparator<String>()
{
public int compare( String key1, String key2 )
{
if( key1 == null )
{
if( key2 == null )
{
return 0;
}
else
{
return 1;
}
}
else
{
if( key2 == null )
{
return -1;
}
else
{
return key1.compareTo( key2 );
}
}
}
} );
for( String s : eventMap.keySet() )
{
mapTest.put( eventMap.get( s ), s ); //Error at this line
}
}
As per my knowledge eventMap doesnot allow null values, hence keyset of eventMap does not have any null values,
if value of any key in eventMap is null, while i try to put it in mapTest, it shoukd not throw any null pointer exception, because its respective comparator allows null values
But why am i getting this exception
java.lang.NullPointerException
at java.util.TreeMap.cmp(TreeMap.java:1911)
at java.util.TreeMap.get(TreeMap.java:1835)
at kidiho.sa.client.reports.ReportEntry.initializemapTest(TestEntry.java:22)
It will throw NullPointerException because in TreeMap api get() method is throwing NullPointerException deliberately if that is null.
final Entry<K,V> getEntry(Object key) {
// Offload comparator-based version for sake of performance
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
Comparable<? super K> k = (Comparable<? super K>) key;
Entry<K,V> p = root;
while (p != null) {
int cmp = k.compareTo(p.key);
if (cmp < 0)
p = p.left;
else if (cmp > 0)
p = p.right;
else
return p;
}
return null;
}
From TreeMap:
final Entry<K,V> getEntry(Object key) {
// Offload comparator-based version for sake of performance
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
Comparable<? super K> k = (Comparable<? super K>) key;
Entry<K,V> p = root;
while (p != null) {
int cmp = k.compareTo(p.key);
if (cmp < 0)
p = p.left;
else if (cmp > 0)
p = p.right;
else
return p;
}
return null;
}
That is: TreeMap doesn't allow null keys, so you cannot do:
tm.put(null, something)
And subsequently, you cannot do
tm.get(null)
As according to the TreeMap behaviour, those operations actually don't make sense
As other said, you can't use a null value as a TreeMap key, it will throw a NullPointerException.
You're not getting the NullPointerException from the same place probably because your first map has a registered comparator and the second has none.

HashMap Duplicate Values - Identify the duplicates

I understand that HashMap doesn't allow insertion of duplicate values and it replaces the last duplicate value with the latest entry.
Is there a way to print the duplicates which were found during the put method?
I have the following code snippet:
for( int i = 0; i <= elements.length - 1; i++) {
nodeDBList = (NodeList) xPath.compile(elements[i]).evaluate(dbDocument, XPathConstants.NODESET);
for (int j = 0; j < nodeDBList.getLength(); j++) {
if(nodeDBList.item(j).getFirstChild() != null)
dbList.put(nodeDBList.item(j).getFirstChild().getNodeValue().toLowerCase().trim(),
nodeDBList.item(j).getNodeName().toLowerCase().trim());
}
}
Wrong. HashMap does not support duplicate keys, which are hashed.
Duplicate values are totally acceptable for different keys.
You can search for existing values by iterating them through the values() method and using the equals method.
Edit
There seems to be a confusion between keys and values here.
According to the HashMap implementation of Map's public V put(K key, V value);, the method put will return the original value for a given key if any, or null.
Quote from the API
#return 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.)
Well, the answer can be found in the API description of HashMap: The put method returns the value that was previously associated with the key.
Returns:
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.)
The old value of the key is returned by the put method, so you can output it.
Assuming the value of your HashMap is of type String :
for( int i = 0; i <= elements.length - 1; i++)
{
nodeDBList = (NodeList) xPath.compile(elements[i]).evaluate(dbDocument, XPathConstants.NODESET);
for (int j = 0; j < nodeDBList.getLength(); j++) {
if(nodeDBList.item(j).getFirstChild() != null) {
String oldVal = dbList.put(nodeDBList.item(j).getFirstChild().getNodeValue().toLowerCase().trim(), nodeDBList.item(j).getNodeName().toLowerCase().trim());
if (oldVal != null) {
System.out.println(oldVal);
}
}
}
}
Override the HashMap
this is an example
public class MyMap<K, V> extends HashMap<K,V> {
private static final long serialVersionUID = -1006394139781809796L;
#SuppressWarnings({ "unchecked" })
#Override
public V put(K key, V value) {
if (value == null) {
return super.put(key, value);
}
if (value.getClass() == Timestamp.class) {
DateFormat dateTimeFormatter;
dateTimeFormatter = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, getLocale());
super.put((K) (key + "_f"), (V) dateTimeFormatter.format(new Date(((Timestamp) value).getTime())));
DateFormat dateFormatter;
dateFormatter = DateFormat.getDateInstance(DateFormat.SHORT, getLocale());
super.put((K) (key + "_f_date"), (V) dateFormatter.format(new Date(((Timestamp) value).getTime())));
}
if (value.getClass() == java.sql.Date.class) {
DateFormat dateFormatter;
dateFormatter = DateFormat.getDateInstance(DateFormat.SHORT, getLocale());
super.put((K) (key + "_f"), (V) dateFormatter.format(new Date(((java.sql.Date) value).getTime())));
}
return super.put(key, value);
}
}

Access a Map's key-value pair as an object

Given a Java Map in which both the key and the value are serializable, I want to be able to serialize the key-value pair. Is there any efficient way that given the key I could retrieve the key-value pair as an object and serialize that? I've seen the entrySet() method for the map class but I don't like to search for the pair twice.
map does not provides such method. But what Still you can do you can, by extending the Map implementation as example - HashMap<K,V> and implement such method like -
Map<K,V> map = new HashMap<K,V>(){
public Entry<K,V> get(Object key) { // overloading get method in subclass
if (key == null)
return getForNullKey();
int hash = hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
return e;
}
return null;
}
private Entry<K,V> getForNullKey() {
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null)
return e;
}
return null;
}};
...
Map.Entry<K,V> entry1 = map.get(key);// invoking Entry<K,V> get(Object key)
You can serialize it as an array:
Object obj = new Object[] {key, value}
obj is Serializable as soon as key and value are Serializable

Categories