3

I have HashMap 1, which contains 5 keys, all of which have Hashmaps as values. I want to add key/value pairs to these sub-Maps.

map1.get(subCategoryMap).put(newKey, newValue); 

My thinking is:

map1.get(subCategoryMap);

returns another map. I could split this line into two lines and have:

map2 = map1.get(subCategoryMap);
map2.put(newKey, newValue);

But I would MUCH prefer to do it in one step. Which is why I am trying

map1.get(subCategoryMap).put(newKey, newValue); 

This doesn't work (doesn't like .put() on an object). Is it possible to access the sub-Map and add to it in the same line of code like I am above, or do I need to split this into 2 lines?

2
  • 5
    Just a comment, when I see maps of maps this is normally a code-smell that indicates that there should be defining your own classes that represent the data structure. Commented Sep 1, 2009 at 15:34
  • 1
    It shouldn't be closed. It's a valid question. However, you should accept the answer that is closest to your solution, or post an answer, wait a few days, and accept that. Commented Sep 1, 2009 at 15:36

8 Answers 8

15

With generics you can:

Map<String, Map<String, String>> map1 = ...
map1.get(category).put(subcategory, value);

If the maps aren't generic:

Map map1 = ...
((Map)map1.get(category)).put(subcategory, value);
Sign up to request clarification or add additional context in comments.

Comments

9
((Map)map1.get(subCategoryMap)).put(newKey, newValue);

Or, use generics:

Map<X, Map<Y,Z>> map1;

...

map1.get(subCategoryMap).put(newKey, newValue);

However, both techniques will fail with NullPointerException if map1 doesn't contain a mapping for subCategoryMap.

Comments

3

Just an aside (I'd make this a comment but I think it will be slightly long)...

It feels very good for a programmer to be able to get a single conceptual operation on one line. To the programmer (at the time) it feels more readable, logical and just feels right.

It is almost never a good thing. For one thing, later it will be harder to parse than two lines--even if your gut reaction now is that it is more readable. Also--the more operations on one line, the harder it is to debug.

For readability, I'd say the Generics solution is about as much as I'd put on a single line--for the casting solution I'd break it down into two lines; I'd also break it down into multiple lines if either of the parameters were operations instead of just simple variables.

I know a lot of people won't agree with this and to tell you the truth I tend to put quite a bit on one line at first, but what I've noticed is that at the first sign of trouble or any confusion, it makes my life easier to break everything down into separate statements with clearly named variables.

At least as important--in cases with nested collections, I will often wrap the collections in a different object as well. This would be interesting in your case--the call would become a little more clear.

dataHolder.put(category, newKey, newVale);

Hides the mechanics of the nesting of the collections (which otherwise can be complex to remember correctly and easy to screw up) and makes your intent much clearer.

This pattern of wrapping (Not extending but encapsulating) nested collections feels strange at first but I really suggest you just give it a try--it really cleans up a LOT of code, makes everything much safer adds to everybody's comprehension, changes a "Collection" to a business object (where you can place business methods--a refactoring you will appreciate almost immediately), and just generally helps your code all over.

2 Comments

did you define a new class/object for dataHolder that has a method for taking a category, newKey, and newValue as input? (or would you, if implementing this?) Not sure I understand what you mean...
@hatorade Yes, dataHolder would contain the nested collections that you suggested. This enforces the structure by protecting against misunderstandings and illegal manipulations. It also allows you to re-implement the data structure without touching the API.
0

If you aren't using Generics, then a HashMap stores and retrieves the keys and values as Object, so you might need to cast, which would look something like this:

((HashMap)map1.get(subCategoryMap)).put(newKey, newValue);

However, it would be helpful if you provided more code.

Comments

0

If you use Generic collections, then your code should work as written. Otherwise, you need to add in the appropriate casts into your single line.

Comments

0

As long as map1 is declared something like Map<OuterKey, Map<InnerKey, MyValue>>, a one-liner will work. However, you need to be careful about what happens if subCategoryMap doesn't exist in map1—a one-liner will raise a NullPointerException.

Comments

0

Works fine if you use generics:

Map<String,Map<String,Integer>> map = new HashMap<String,Map<String,Integer>>();
map.put("Test", new HashMap<String,Integer>());
map.get("Test").put("Some", 1);

Comments

0

You can use ((HashMap)map1.get(subCategoryMap)).put(newKey, newValue);

Also, if you are using Java 5 or Java 6, you can use generic to avoid the cast in HashMap

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.