2

So , I want to make a map of Lists of Strings to Strings, but I cannot get it to work properly:

this is all the code I have done, and until i can find out why, I cannot progress:

Map<List<String>, String> test = new HashMap<List<String>, String>();
test.put( new ArrayList<String>(), "s1");
test.put( new ArrayList<String>(), "s2");
test.put( new ArrayList<String>(), "s3");

System.out.println(test.size());

i get 1, it should be 3!! Why is only one object getting added when I made 3 calls, for 3 separate objects? I know the danger of accidentally adding in the same object to a collection, but I specifically created a new ArrayList for each put, thus creating a total brand new object.

So why is there only one object in the Map then? Thanks!

1
  • 2
    You should never use a mutable key in a HashMap. Commented Feb 12, 2013 at 5:28

5 Answers 5

3

The ArrayList#hashCode() is returning the same for all of them. If you look at the sourcing for it: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/AbstractList.java#AbstractList.hashCode%28%29

You can see that should there be no elements, or all the same elements, that the hashCode would be the same.

Fix that up and it should work fine. Use either a Map or change the hashCode in one way or another.

Sign up to request clarification or add additional context in comments.

2 Comments

thanks!how do i change the hashCode? would a TreeMap fix the problem?
That would work great. You could override ArrayList and just change the hashCode method. For example, make it have a unique ID such as for example: time of creation, a randomly generated number, etc.
3

Try this:

Map<String,List<String>> test = new HashMap<String,List<String>>();
test.put("s1", new ArrayList<String>());
test.put("s2", new ArrayList<String>());
test.put("s3", new ArrayList<String>());

System.out.println(test.size());

Note that a map is a key-value relation. For this reason, you may want too use the String as a key and the ArrayList as the values, instead of the other way around. This way, if you add 3 different Strings, each one will have a different hash value (hashcode). Thus, you will have 3 different keys in your Map.

Note also that:

put

public Object put(Object key, Object value) Associates the specified value with the specified key in this map. If the map previously contained a mapping for this key, the old value is replaced.

This is why you are getting 1, instead of 3, because you were adding the same object new ArrayList<String>().

Take look in more detail into the Class HashM specifications.

Comments

1

You use ArrayList as the key, try

    System.out.println(new ArrayList<String>().equals(new ArrayList<String>()));

it prints

true

1 Comment

The general contract for hashCode is: If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
0

The best approach would be to use the String object as key and the List as value.

Have a look at what java docs say here.

And if at all you want to add the ArrayList as key then overriding equals method should suffice.

The post here gives good insights. I have put some which I liked from that post.

Overriding equals for two ArrayLists:

 public boolean equals(List<String> one, List<String> two){
    if (one == null && two == null){
        return true;
    }

    if((one == null && two != null) 
      || one != null && two == null
      || one.size() != two.size()){
        return false;
    }

    //to avoid messing the order of the lists we will use a copy
    //as noted in comments by A. R. S.
    one = new ArrayList<String>(one); 
    two = new ArrayList<String>(two);   

    Collections.sort(one);
    Collections.sort(two);      
    return one.equals(two);
}

2 Comments

how do i override the equals method?
But just to confirm once again do you really need ArrayList as key?
0

I'm not sure why you need the list as the key and the string as the value, but you are basically using the same 'key' for each put operation since the hashcode is the same for any empty list. Like the other answers mention, it's probably best to switch the list as the value and the string as the key. If the list changes, any future attempts at .get will return null

   public static void main(String...args) {
       Map<List<String>, String> test = new HashMap<List<String>, String>();
       List<String> bob = new ArrayList<>();
       bob.add("asdf");
       test.put( new ArrayList<String>(), "s1");
       test.put( bob, "s2");

       System.out.println(test.size());
       System.out.println(test.get(bob));
   }

outputs

2
s2

When a new item gets added like

   public static void main(String...args) {
       Map<List<String>, String> test = new HashMap<List<String>, String>();
       List<String> bob = new ArrayList<>();
       bob.add("asdf");
       test.put( new ArrayList<String>(), "s1");
       test.put( bob, "s2");      
       bob.add("aabbcc");

       System.out.println(test.size());
       System.out.println(test.get(bob));
   }

The get will not work, since the hash of the list has changed. The output in this case would be:

2
null

Comments

Your Answer

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.