Home > database >  When should implementations/extensions of an interface NOT return more specific types than those dec
When should implementations/extensions of an interface NOT return more specific types than those dec

Time:09-25

Java allows me to define an implementation of an interface that overrides its methods with ones that return a subclasses of the interface's return type. For example:

public interface GoblinHorde {
    Collection<Goblin> getGoblins();
}

public final class UniqueGoblinHorde implements GoblinHorde {
    private Set<Goblins> currentGoblins = new HashSet<>();
    
    @Override
    public Set<Goblin> getGoblins() {
        return currentGoblins;
    }
} 

This makes perfect sense to me because it gives developers an opportunity to make a tradeoff between code maintainability and performance. If you are going to use the results of GoblinHorde#getGoblins() as a Set, you should have the option of declaring your GoblinHorde's type as the impl instead of the interface. This allows you to use the returned Set instead of unnecessarily building a new set from a Collection that is already a Set. Obviously this comes at the cost of code that is less maintainable in the long run, but there are situations where it makes sense.

However, Google doesn't seem to always follow this pattern. Guava 30.1.1's AbstractSetMultimap#asMap() method returns the more general Map<K, Collection<V>> instead of Map<K, Set<V>> and goes so far to include a note in the Javadocs that reads Note: The returned map's values are guaranteed to be of type Set. To obtain this map with the more specific generic type Map<K, Set<V>>, call Multimaps.asMap(SetMultimap) instead.

What is the impetus for requiring the use of a secondary static helper method?

CodePudding user response:

The only reason I could see is that covariant return types were not supported before Java version 1.5 released in September 2004 so it was impossible to return a more specific type then. Not sure when that library was written, but I can only assumed it was written when this was not supported.

CodePudding user response:

I can see a single reason: they want to keep the possibility of changing the implementation to return a List instead of a Set for example and avoid breaking a lot of applications relying on a return object of Map<K, Set<V>>. Of course, this hypothetical change would most probably mean that your code would need to change to adjust your business logic (maybe you were relying on the no duplicates "feature" of Set), but at least your code would still compile (unless you do some casting).

  • Related