Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extending Guava collections

Tags:

java

guava

I wanted to extend LinkedHashMultimap (Guava 16.0.1), mostly to add methods that return commonly used pre-populated maps.

public class MyMap extends LinkedHashMultimap<String, Object> {
}

But, as I learned, most Guava collections are final, and those that are not, don't expose public constructors. What are the possible reasons for this design decision? And what would be the best approach to achieve my goal? The best I can think of is to wrap Multimap methods in my class, but that is far from ideal.

EDIT:

Some users pointed to valid reasons for not allowing inheritance. To extend the questions a little bit, I would like to point out couple of things.

  1. If inheritance is not recommended in public API, how come Java's own collection classes are not final?

  2. Suppose I extensively use a following class:

LinkedHashMultimap<Class<? extends BaseEntity>, BiConsumer<? extends BaseEntity, ? extends Object>>

Now, that's a mouthful. If I could just:

public class ConsumerMap extends LinkedHashMultimap<Class<? extends BaseEntity>, BiConsumer<? extends BaseEntity, ? extends Object>> {
}

I could then use ConsumerMap in my code instead of that monstrosity. I believe readability alone would be reason enough to justify inheritance.

like image 274
Nikša Baldun Avatar asked Dec 19 '22 05:12

Nikša Baldun


2 Answers

As others have pointed out, you should prefer delegation to inheritance.

What you want to do to implement the class you want is to extend ForwardingSetMultimap, using a LinkedHashMultimap as the delegate. Here's an example of how that'd look:

public final class MyMap extends ForwardingSetMultimap<String, Object> {
  private final SetMultimap<String, Object> delegate =
      LinkedHashMultimap.create();

  @Override public SetMultimap<String, Object> delegate() {
    return delegate;
  }

  // add your methods here
}

Aside: You ask "If inheritance if not recommended in public API, how come Java's own collection classes are not final?"

I think the answer is basically that it was a mistake not making Java's own collection classes final (note: some of them, particularly newer ones, actually are final). As @Mick Mnemonic notes, Josh Bloch (who designed the original collection APIs) was involved in the design of Guava's collection APIs: the design decisions in Guava's API reflect lessons learned from the original collection APIs.

like image 51
ColinD Avatar answered Dec 21 '22 19:12

ColinD


These classes were designed not to be extended. Because inheritance essentially breaks encapsulation, it makes the API cleaner when classes can't be extended. (Related thread here: Good reasons to prohibit inheritance in Java?)

You can generally work around this by using composition instead.

To answer your follow-up questions:

Regarding Java Collections API, I think there are two alternatives: either classes like ArrayList or HashMap were designed to be extended or then this is simply an API design flaw. I suspect the latter; but it is impossible to revert this design choice after the API has been published. Perhaps only abstract classes such as AbstractList should have been declared non-final?

Probably the Guava team thought that use cases such as the one you present are so rare that it's not worth the effort to add support for inheritance (YAGNI).

This talk by Josh Bloch — who's been involved in designing both the Java API and Guava — is an excellent presentation on the topic.

like image 30
Mick Mnemonic Avatar answered Dec 21 '22 18:12

Mick Mnemonic