8

My question is rather a design question. In my program I got to a data structure that looks something like this:

private ConcurrentHashMap<A, ConcurrentHashMap<B, ConcurrentHashMap<Integer, C>>> services  = new ConcurrentHashMap<A, ConcurrentHashMap<B, ConcurrentHashMap<Integer, C>>>();

Is there a way to handle such a data structure more elegantly? Thanks!

edit: A, B and C are business classes. An A instance "can have" (as association) many Bs and a B "can have" many mappings Integer-C.

8
  • What types are A, B, and C? It would be easier to answer if I could understand the meaning of three-level nesting of your has maps there. Commented Jan 13, 2012 at 15:20
  • 1
    Without knowing something about the domain, I don't think there's a general solution. Depending on how the maps are being used, you might consider replace one or more of the maps with classes that export a specific set of properties. Commented Jan 13, 2012 at 15:22
  • 4
    Consider using objects encapsulating behavior, rather than dumb datastructures. Each of these maps should probably be wrapped into a specific object.
    – JB Nizet
    Commented Jan 13, 2012 at 15:25
  • As an aside, do you really need to use ConcurrentHashMaps at every level of nesting?
    – Russell
    Commented Jan 13, 2012 at 15:26
  • @ErnestFriedman-Hill: I was thinking that it may be so - that there is no "general solution", only a business-related one.
    – ovdsrn
    Commented Jan 13, 2012 at 15:28

2 Answers 2

16

Create a class Triple with fields for A,B,Integer, override hashCode() and equals(), and use Map<Triple,C> instead of Map<A,Map<B,Map<Integer,C>>>

In this approach - you put all elements in one map, with a larger possible range of keys.

4
  • Will the downvoter explain? I assumed here the OP actually is trying to map : (A,B,Integer) -> C, and thus the nested Map usage. The edit also supports my preception.
    – amit
    Commented Jan 13, 2012 at 15:30
  • 2
    Correct, this is what I'm trying to map: (A, B, Integer) to C.
    – ovdsrn
    Commented Jan 13, 2012 at 15:34
  • I'll also add, name the Triple class something meaningful in your business domain. It must mean something :-) Commented Jan 14, 2012 at 10:37
  • Because of the contract of equals, this will only work if the keys form an equivalence relation. I recently encountered a situation like this where they didn't: the third component of the key could either be a default value that would accept any instance, or some concrete value, with all concrete values being different from each other. Thus any concrete value would have to be considered equal to the default one, and by transitivity they would all have to be equal to each other, which they weren't.
    – G. Bach
    Commented Jul 6, 2015 at 21:02
6

[I come from C# background, but the answer should apply]

[It doesn't much matter but I assume the last item is ConcurrentHashMap<C,Integer>]

You have a function f of type A --> (B --> (C --> int)) If it is really what you need, I don't have a ready answer. But perhaps, having a function f of type (A x B x C) --> int would be enough for your purposes.

The difference between two cases is, the first one is lazier, more functional, arguably more elegant and it is possible to have a "partially applied" function around. For example, you have an a (of type A) element, you apply a to f and have a function g of type (B --> (C --> int)) to pass around, send to methods, whatever. However it is a little cumbersome and a little more code to properly initialize the function.

The second is more eager and less elegant, but may be easier to code and understand. All you need to do is to have a generic class Triple<A,B,C>, override Equals() and GetHashCode() so that it will have value semantics, (two instances are to be considered equal if they have equal elements) and declare the ConcurrentHashMap is from Triple to Integer. The most obvious cost to pay is you need to have the A, B, C elements ready all at once to create an instance of Triple and perform the lookup.

Edit: If the last item is really ConcurrentHashMap<C,Integer>, then your generic class will have A, B and Integer fields, and the mapping will be from Triple<A,B,Integer> to C

2
  • Maybe call it Triple instead of MyClass to clarify; there are also n-tuple implementations around the web, if you are really lazy.
    – Viruzzo
    Commented Jan 13, 2012 at 15:50
  • Actually, the last map is ConcurrentHashMap<Integer, C>, not ConcurrentHashMap<C, Integer>, but it's just a minor detail, since from your answer I see you understood it correct.
    – ovdsrn
    Commented Jan 16, 2012 at 10:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.