Key in TreeMap returning null

So, I have a very strange error. I came across it when I initially used keySet () to repeat the first 10 keys of a large TreeMap. One of the keys returned null, which should not be possible, as I understand it. 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 turned off the card after the first ten, as there are much more, but all this is a key with a value.

So my question is this: why do I get zero when using the key to directly obtain (the key) from the TreeMap, but the EntrySet returns the correct key and value?

Here is my comparator as I order 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 TreeMap is built as follows:

 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>

+6
source share
4 answers

Problem resolved:

 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)).intValue() < ((Integer) base.get(b)).intValue()) { return 1; } else if ( ((Integer) base.get(a)).intValue() == ((Integer) base.get(b)).intValue()) { return ((String)a).compareTo(((String)b)); } else { return -1; } } } 

This has the added benefit of returning keys with the same value in alphabetical order.

+1
source

Of the order of iterations displayed in your TreeMap , of course you used a custom Comparator . [Otherwise the iteration would be in lexicographical order]

Please note that according to javadocs :

The developer must ensure that sgn (compare (x, y)) == -sgn (compare (y, x)) for all x and y. (This means that a comparison (x, y) should throw an exception if and only if the comparison (y, x) throws an exception.)

The developer must also ensure that the relation is transitive: ((cf. (x, y)> 0) && (cf. (y, z)> 0)) implies a comparison (x, z)> 0.

Finally, the developer must ensure that comparing (x, y) == 0 implies that sgn (cf. (x, z)) == sgn (cf. (y, z)) for all z.

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

EDIT: [in response to the amended question]
Your comparter uses the identifier [ operator== ] to check for two integers.
Note that Integer is an object - and thus operator== returns 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()

+7
source

The biggest problem is that using == instead of .equals in your value comparator is a violation of things because different keys get mapped to different Integer objects with the same intValue() , which discards even more things unpredictably.

But if you fixed it, then your TreeMap will not allow you to insert multiple keys with the same value, which almost certainly also causes subtle breakdowns.

The best solution would be something like this , but basically you have to fill in the map without sorting by value, sort entrySet , and then copy the entries (in order) to a map like LinkedHashMap , which does not need a comparator, but simply saves the entries in insertion order .

Perhaps you can change your comparator so that if the values ​​match, they also compare keys. This will at least allow you to insert multiple keys with the same value ... but it is still a very hacky solution, much more risky than the LinkedHashMap based LinkedHashMap , as described above.

+3
source

You just need to:

 class ValueComparator implements Comparator<Integer> { public int compare(Integer a, Integer b) { return a.compareTo(b); } } 

Then you need to initialize your treemap using a comparator and add all your elements:

Treemap

0
source

Source: https://habr.com/ru/post/909304/


All Articles