1

I am getting unexpected results from a Set of Maps (Set<Map<String,String>>), where s.contains(s.iterator().next()) is false.

The set in question contains only one map that is [{=262.666666666666667}] (the empty String mapped to the String 262.666666666666667).

I have been unable to put together a minimal working example that replicates the problem as the following outputs true:

Set s = new HashSet<Map<String,String>>();
Map<String,String> m = new HashMap<>();
m.put("", "262.666666666666667");
s.add(m);
System.out.println(s.contains(s.iterator().next()));

HashMap does not override hashCode but Abstract map does (see below) so I don't see the problem of putting a HashMap in a HashSet.

public int hashCode()
{
 int h = 0;
 Iterator<Entry<K,V>> i = entrySet().iterator();
 while (i.hasNext())
 h += i.next().hashCode();
 return h;
}

What is the reason for this behaviour and how can I fix it?

Edit: Thanks at doublep and morgano, I indeed modified the map after adding it and resolved the issue by adding after the modification instead of before.

asked Mar 26, 2015 at 10:40
9
  • Multiple threads? Until we've got something which reproduces the problem, it's hard to help... Commented Mar 26, 2015 at 10:43
  • Your self-contained example returns true when executed on a single thread. Commented Mar 26, 2015 at 10:43
  • What do you mean by unexpected results? Commented Mar 26, 2015 at 10:43
  • Perhaps some rounding issue? Commented Mar 26, 2015 at 10:44
  • 4
    If you modify a member map after adding it to the set, and thus changing map's hashcode, set will become broken. That's the reason Python, for example, requires that dictionary keys are immutable. Commented Mar 26, 2015 at 10:49

1 Answer 1

3

If you want to reproduce the error, modify your code in this way:

 Set s = new HashSet<Map<String,String>>();
 Map<String,String> m = new HashMap<>();
 s.add(m);
 m.put("", "262.666666666666667");
 System.out.println(s.contains(s.iterator().next()));

That is, add the map to the set and then put a new key/value in the map.

The problem is that, as you said, Abstract map overrides equals() to depend on the key/values that the map holds at that moment. Set uses internally a Map, being the key the value of equals() at the moment your Map is being added to the set. When you add a new key/value to your Map then the value returned by equals() also changes and doesn't correspond to the original value, this way you get false for System.out.println(s.contains(s.iterator().next()));

answered Mar 26, 2015 at 10:52

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.