tags:

views:

491

answers:

8

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?

+7  A: 
((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.

Andrew Duffy
+1 for mentioning the NPE
Dan
A: 

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.

Thomas Owens
A: 

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.

R. Bemrose
A: 
erickson
+9  A: 

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);
cletus
A: 

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

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

Nettogrof
A: 

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);
Fabian Steeg
+2  A: 

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.

Bill K
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
@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.
Bill K