Use nested generic collections or custom intermediate classes?

Before introducing Java to generics, I would write classes that encapsulate collections-of-collections-of-collections. For example:

class Account { private Map tradesByRegion; //KEY=Region, VALUE=TradeCollection } class TradeCollection { private Map tradesByInstrument; //KEY=Instrument, Value=Trade } 

Of course, with generics, I can just do:

 class Account { private Map<Region, Map<Instrument, Trade>> trades; } 

Now I prefer option No. 2 (according to the extended version of option No. 1), because this means that I do not get the distribution of classes that exist solely for the purpose of packaging the collection. But I feel that this is a bad design (for example, how many nested collections should I use before declaring new classes). Opinions?

+6
java generics oop
source share
7 answers

2 is better because:

  • Less code performs the same effect (better, in fact, as in # 1 there is some information of your type only in the comments)
  • It’s very clear what is happening on.
  • Errors of your type will be detected at compile time.

What can I recommend 1? admittedly, Integer, Map <String, <Map <... generics are a little difficult to get used to, but in my opinion it is much easier to understand than code with maps, map lists and map map lists and custom objects full of map lists.

+4
source share

The combination of two. Although you can use generics to replace custom classes, you still want to use a class to encapsulate your concepts. If you simply transfer card cards to card lists to everyone who controls what can you add? who controls what you can remove?

For storing data, generics are a great thing. But you still want the methods to check when you add a deal or add an account, and without any class wrapping your collections, no one controls it.

+4
source share

I made this simple rule for me: no more than two <and two commas in the generics declaration and preferably only one comma. After that I introduce custom types. I think this is the moment when readability is enough to guarantee additional concepts.

There is a real good reason to avoid being too deep generics: the difficulty lies not only in the actual declaration, but usually tends to be equally visible in the logic of construction. Thus, a lot of code tends to get confusing if you insert these statements too deeply. Creating intermediate classes can help. The trick is often to look for appropriate intermediate classes.

I definitely think you should go back to your old standard a bit. In fact, your second sample is the exact point of pain, where I still only take generics.

+2
source share

Typically, collections also have some code. When it becomes non-trivial, I put together a collection with behavior in a new class. The deeper the nesting, the more likely it will be.

+2
source share

I think it’s better to keep objects in mind and emphasize collections a little less. Rating is your friend.

For example, it’s natural that you have Student and Course objects if you are modeling a system for a school. Where should grades be captured? I would say that they belong to the object where Student and Course meet - ReportCard. I would not have a GradeCollection class. Give him some real behavior.

+2
source share

I prefer # 2. It is clearer what happens and is typical at compile time (I prefer that there are as many errors as possible during compilation, as opposed to those that occur at runtime ... In general, I like when nothing happens).

Edit:

Well, there are two ways that I can see ... I think it depends on what you will use:

 class Account { private Map<Region, TradeCollection> tradesByRegion; } class TradeCollection { private Map<Instrument, Trade> tradesByInstrument; } 

or

 class Account<R extends Region, I extends Instrument, T extends Trade, C extends TradeCollection<I, T>> { private Map<R, C> tradesByRegion; } class TradeCollection<I extends Instrument, T extends Trade> { private Map<I, T> tradesByInstrument; } 
+1
source share

I think the answer to this question is that it depends on the situation. Typically, introducing a type is useful if it also introduces type-related methods, if these intermediate types are passed independently, etc.

You can find this little tip from Rich Hickey (creator of Clojure) on creating interoperable libraries of interest:

It was intended as concrete advice for Clojure librarians, but I think it is interesting food for thought, even in Java.

+1
source share

All Articles