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);
}
}
Related
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++; // <---------------
}
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.
In the documentations, the return type for the HashMap or Hashtable is the value itself as following,
public V put(K key, V value)
and, it tells about the return type is 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.)
Say, if I write a Hashtable as following,
Hashtable<Integer, Character> hash = new Hashtable<Integer, Character>();
System.out.println(hash.put(12, 'c'));
Now, the above code returns null. I'm implementing a Hashtable and I'm slightly confused when to return null or V where V will be the previous value associated with key. My code is as following,
// for dealing w/ the table data
class HashEntry<K, V> {
private final K key;
private V value;
public HashEntry(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
}
class MyHashTable <K, V> {
private int size;
private int DEFAULT_CAPACITY = 16;
private HashEntry<K, V>[] values = new HashEntry[DEFAULT_CAPACITY];
public V put(K key, V value) {
boolean insert = true;
for (int i = 0; i < size; i++) {
if (values[i].getKey().equals(key)) {
values[i].setValue(value);
insert = false;
}
}
if (insert) {
// method for check or increase capacity
increaseCapacity();
values[size++] = new HashEntry<K, V>(key, value);
}
return null;
// return value;
}
When should I return null or value ( type V) in the implementation ?
In your example this is your first time assigning a value to the key 12 so as stated in the documentation null is returned since there was no previous value stored for that key.
If you then did:
System.out.println(hash.put(12, 'd'));
'c' would be printed because it is returned as the previous value for the key 12.
Edit based on additional info in question:
Here is a possible implementation of your put method to return the previous value correctly.
public V put(K key, V value) {
boolean insert = true;
V prevValue = null;
for (int i = 0; i < size; i++) {
if (values[i].getKey().equals(key)) {
prevValue = values[i].getValue();
values[i].setValue(value);
insert = false;
}
}
if (insert) {
// method for check or increase capacity
increaseCapacity();
values[size++] = new HashEntry<K, V>(key, value);
}
return prevValue;
}
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.
This is somewhat of a methodology question. I am storing pairs of generics and when I store data into my array I want to only return the previous value. I am having a hard time figuring out how to return either the value in that previous location or null, if it was previously in that state.
Below you'll see what I'm trying to do.
public V put(K key, V value) {
if (value == null) {
throw new NullPointerException("The value you are trying to pass is null.");
}
if (size == table.length){
enlarge();
}
int loc = 0;
while (loc < size){
if (table[loc].value.compareTo(value) < 0){
loc++;
}else{
break;
}
}
for (int index = size; index > loc; index--)
table[index] = table[index - 1];
Here is where I am trying to actually store the old value.
if (table[loc] != null){
V oldValue = table[loc].value;
table[loc] = new SVData<K, V>(key, value);
size++;
return oldValue;
} else {
table[loc] = new SVData<K, V>(key, value);
size++;
return null;
}
}
The problem I am having is where in the method to actually store the old value ( I think ). Right now I have it in the if block where it checks to see whether or not that index is null, but is returning the new value. When creating method like this where is the best place in the procedure to try to store that value?
I'm also trying to move on from hack code to nice clean code so any additional advice in that arena would be great.