Best Practices for Using Multi Level HashMap in Ja

2019-05-07 14:11发布

问题:

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;
}

回答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).



回答2:

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.



回答3:

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.