Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Key in TreeMap returning null

Tags:

java

treemap

So I have a very odd bug. I stumbled across it when I was originally using a keySet() to iterate over the first 10 keys of a large TreeMap. One of the keys was returning null, which should not be possible as far as my understanding goes. So I wrote the test code below:

int i = 0;
        for (Map.Entry<String, Integer> es : sortedMap.entrySet()){
            if (i >= 10) {
                break;
            }

            if (sortedMap.containsKey(es.getKey())){
                System.out.println(es.getKey() + ":" + sortedMap.get(es.getKey()));
            } else {
                System.out.println("Key " + es.getKey() + " does not exist, yet...");
                System.out.println("This does work: " + es.getKey() + ":" + es.getValue());
                System.out.println("This does NOT work: " + es.getKey() + ":" + sortedMap.get(es.getKey()));
            }
            i++;
        }

And get the following results:

SOAP:967
'excerpt'::679
'type'::679
Key 'author_url': does not exist, yet...
This does work: 'author_url'::679
This does NOT work: 'author_url'::null
'date'::679
Android:437
TLS:295
message:283
server:230
monthly:215
<<<<<<<<<<<<<<<<<<<<DUMPING MAP!
{SOAP=967, 'excerpt':=679, 'type':=679, 'author_url':=679, 'date':=679, Android=437, TLS=295, message=283, server=230, monthly=215...

I cut off the map after the top ten as there is a lot more in there, but all of it is a key with a value.

So my question is this: Why am I getting a null when using the key to directly get(key) from the TreeMap, but the EntrySet returns the correct key and value?

Here is my comparator since I am ordering on Integer:

class ValueComparator implements Comparator<Object> {

  Map<String, Integer> base;
  public ValueComparator(Map<String, Integer> base) {
      this.base = base;
  }

  public int compare(Object a, Object b) {

    if ((Integer) base.get(a) < (Integer) base.get(b)) {
      return 1;
    } else if ((Integer) base.get(a) == (Integer) base.get(b)) {
      return 0;
    } else {
      return -1;
    }
  }
}

And the TreeMap is built as following:

ValueComparator bvc =  new ValueComparator(allMatches);
TreeMap<String, Integer> sortedMap = new TreeMap<String, Integer>(bvc);
//Sort the HashMap
sortedMap.putAll(allMatches);

Where allMatches is a HashMap<String, Integer>

like image 720
Dennis Sullivan Avatar asked Feb 24 '12 19:02

Dennis Sullivan


People also ask

Can a key of TreeMap be null?

A TreeMap contains values based on the key. It implements the NavigableMap interface and extends AbstractMap class. It contains only unique elements. It cannot have null key but can have multiple null values.

What happens when a null key is added to a TreeMap?

Null Keys and Null Values What if we try to add one more element with a null key? TreeMap sorts elements in natural order and doesn't allow null keys because compareTo() method throws NullPointerException if compared with null.

Can we have null key in HashMap TreeMap?

HashMap allows storing at most one null key and many null values. However, TreeMap doesn't allow a null key but may contain many null values. If we're using a TreeMap with a user-defined Comparator, then it depends on the implementation of the compare() method how null values get handled.

How do I get TreeMap key-value?

The process is divided into three steps: Use the entrySet() method of the TreeMap class to get a Set view of all the entries stored in the TreeMap object. Convert the entry set to an array using the toArray() method. And get TreeMap key or TreeMap value using index with the help of getKey() and getValue() method.


1 Answers

From the order of iteration your TreeMap shows, it is definetly the case that you used a custom Comparator. [Otherwise the iteration would have been in lexicographical order]

Note that according to the javadocs:

The implementor must ensure that sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and y. (This implies that compare(x, y) must throw an exception if and only if compare(y, x) throws an exception.)

The implementor must also ensure that the relation is transitive: ((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0.

Finally, the implementer must ensure that compare(x, y)==0 implies that sgn(compare(x, z))==sgn(compare(y, z)) for all z.

If your Comparator does not apply these rules - the behavior is not defined, as might show strange results - as you see.

EDIT: [as response to the editted question]
Your compartor uses identity [operator==] to check two Integers.
Note that Integer is an object - and thus operator== will return true only if it is the same object.
You should use equals() to check if two integers are identical - or even better - use Integer.compareTo()

like image 131
amit Avatar answered Oct 24 '22 04:10

amit