Best Practices for Using Multi Level HashMap in Java
Solution 1
As long as they're properly abstracted, it's not that big of a deal, but you lead yourself down some nasty rabbit holes in terms of readability. Without abstraction, maintaining this becomes a nightmare that no developer would wish on another.
Essentially, what you're creating is a table of sorts; the first key is the primary key to gain access to further columns. On a simple one, two, or three-level design, this isn't terrible; you need three keys to get a single value. Provided that there's a convenient way to access it, like the below, it's not a terrible idea (although there are far better out there).
public interface Table<K1, K2, K3, V> {
V get(K1 key1, K2 key2, K3 key3);
}
...However, it all depends on what you're actually doing with that data structure. If you find yourself attempting to iterate intermediate keys for values (that is, you're looking at Key 3 for the collection of all values between it and Key 5), you've got to rethink your business logic at that point. The data structure provided isn't flexible enough to handle all cases; more or less, it's used for simplistic indexing based on a set of values.
Alternatively, one could look into a Guava Table
, as that does the same sort of thing, with a better interface to it (something like the one I have above).
Solution 2
I think doing HashMap
within HashMap
is bad practice, because in order to extend your HashMap to go deeper, will cost you both time and money. Going from 3
level depth Map
to 5
level depth Map
, you would essentially have to re-code your Class. Which will put a lot of technical debt when it comes to maintaining this program.
Declare the Initial Map somewhere
Map<String, MyHashedObject> HashKVP = new HashMap<String, MyHashedObject>();
Then have an Object
to store additional maps.
class MyHashedObject {
private Map<String, MyHashedObject> InternalKvp;
public MyHashedObject() {
this.InternalKvp = new HashMap<String, MyHashedObject>();
}
/*
* Get the next level of our MyHashedObject object
* @param HashKey
* @return MyHashedObject result
*/
public MyHashedObject findHashedObject(String HashKey) {
MyHashedObject result = null;
if(this.InternalKvp.containsKey(HashKey)) {
result = this.InternalKvp.get(HashKey);
}
return result;
}
}
This way, you can easily extend more levels to your HashMap
by simply dumping more Objects into the InternalKvp
.
This just a very basic example, but you can add more properties to the MyHashedObject
(such as depth
, parent_object
etc). You could do something like Small-world network, to track the depth
of each object.
This could also be done better, using a RedBlackTree
or AVLTree
to make it easier to traverse through the Maps
.
Solution 3
Multi-level HashMaps are not necessarily bad, it depends on your algorithm. The bad thing is that it's more difficult to manage. Consider using interfaces (something like repository) for HasMap values, this may make your design cleaner. Other option is to use composite keys in a HashMap.
Related videos on Youtube
anzaan
Updated on September 15, 2022Comments
-
anzaan over 1 year
We have a situation where we are ending up using multi-level hash maps; that is, a hash map inside of a hash map, three or four levels deep.
Instinctively this felt wrong somewhere. I have read posts here that talks about how to iterate/use a multi-level hash map, but hardly any of them say what is the best practice for this.
Why are multi level hash maps bad, and what would be the better design, if any?
Here is the sample design of multi-level hash maps that we have:
Map<String, Object1> map1; class Object1 { String version; Map<String,Object2> map2; } class Object2 { Map<String,List<Object3>> map4; Map<String,String> map5; }
-
Makoto almost 9 yearsI personally would presume that a data structure like this is regarded as a one-off. Tables have their place, but it's uncommon to see them a lot. By the way,
HashKVP
is kind of just hanging around in no-man's land. -
classicjonesynz almost 9 yearsYeah it is in no-man's land, its just an example of the starting object.. which contains
MyHashedObject
. -
Makoto almost 9 yearsSo, I've had a moment to look at this a bit closer...could you explain what the difference is between this solution and what the OP has already provided? It kind of looks the same to me.
-
classicjonesynz almost 9 yearsThe difference is that, in order for OP to make his map 5 levels deep, he has to write
3
new objects, then reference those objects to his existing objects. (newObject4
,Object5
). All I have to do is writeMyHashedObject Object4 = new MyHashedObject()
thenHashKVP.put(StringRef, Object4);
. The difference is the time taken to do this (and the time it takes to maintain the existing code, and create new code). -
Makoto almost 9 yearsSorry, I'm not convinced that there's a difference. At some level (with a bit of indirection), you're still creating multiple maps, it's just with one object instead of several. You also don't enforce or guarantee any type flexibility, so flexibility is sacrificed for maintainability. The layer that the objects add is pretty thin.
-
classicjonesynz almost 9 yearsIt's a basic example, of a different way of declaring maps within maps, with less code (as stated in the answer, it can be extended to make it more abstract and concrete). Obliviously you wouldn't copy/paste this, and say job well done.
-
anzaan almost 9 yearsI went through the code of Guava Table implementation
HashBasedTable
which again uses data structure likeMap<R, Map<C, V>>
. But yes it provides better interface. I was hoping for some drastic change in data representation. Could you give an example of what you mean by proper abstraction for above design? -
anzaan almost 9 yearsI couldn't really get how difficult it will be to manage if the code is properly structured. Could you elaborate on this - "using interfaces (something like repository) for HasMap values".
-
Konstantin Pavlov almost 9 yearsTry to write a unit test on a structure with nested maps and you will see how difficult is it. In this case you'll need an abstractions to simplify the logic.