18

In most Java code, I see people declare Java objects like this:

Map<String, String> hashMap = new HashMap<>();
List<String> list = new ArrayList<>();

instead of:

HashMap<String, String> hashMap = new HashMap<>();
ArrayList<String> list = new ArrayList<>();

Why is there a preference to define the Java object using the interface rather than the implementation that is actually going to be used?

1

4 Answers 4

29

The reason is that the implementation of these interfaces is usually not relevant when handling them, therefore if you oblige the caller to pass a HashMap to a method, then you're essentially obliging which implementation to use. So as a general rule, you're supposed to handle its interface rather than the actual implementation and avoid the pain and suffering which might result in having to change all method signatures using HashMap when you decide you need to use LinkedHashMap instead.

It should be said that there are exceptions to this when implementation is relevant. If you need a map when order is important, then you can require a TreeMap or a LinkedHashMap to be passed, or better still SortedMap which doesn't specify a specific implementation. This obliges the caller to necessarily pass a certain type of implementation of Map and strongly hints that order is important. That said, could you override SortedMap and pass an unsorted one? Yes, of course, however expect bad things to happen as a result.

However best practice still dictates that if it isn't important, you shouldn't use specific implementations. This is true in general. If you're dealing with Dog and Cat which derive from Animal, in order to make best use of inheritance, you should generally avoid having methods specific to Dog or Cat. Rather all methods in Dog or Cat should override methods in Animal and it will save you trouble in the long run.

7
  • When you need a map that is sorted, the parameter type should be SortedMap, not TreeMap.
    – Cephalopod
    Commented Mar 5, 2014 at 9:30
  • @Arian SortedMap is one of several implementations which deal with ordering. That's besides the point. TreeMap also orders items according to the key's implementation of Comparable or given a Comparator interface.
    – Neil
    Commented Mar 6, 2014 at 13:44
  • No, SortedMap is not an implementation, that's exactly the point. It is the interface for maps that sort by key.
    – Cephalopod
    Commented Mar 6, 2014 at 20:43
  • 1
    @Arian Ah I see what you mean. True, better SortedMap since that doesn't force an implementation. I'll make the proper adjustments.
    – Neil
    Commented Mar 7, 2014 at 10:26
  • Actually, a LinkedHashMap doesn't implement SortedMap. The only subclasses of SortedMap are ConcurrentSkipListMap and TreeMap.
    – bcorso
    Commented Aug 8, 2014 at 18:55
11

In Layman's words:

The same reason electric apliances makers built their products with electrical plugs instead of simply peeled out cables, and houses come with wall sockets instead of peel out cables sticking out of the wall.

By using standard plugs instead, they allow to plug the same apliances in any compatible plug around the house.

From the point of view of the wall socket, it doesn't matter whether you plug a TV set or a stereo.

That makes both the appliance and the socket more useful.

Take for example a method that accepts a Map as an argument.

The method willl work regardless of you passing a HashMap or a LinkedHashMap to it, as long it's a subclass of Map.

That's Liskov substitution principle.

In the sample code you gave, it means you can later, for some reason, change the concrete implementation of Hash and you will not need to change the rest of the code.

The problem with software is that, since it's relatively easy to change things later with no waste of bricks or mortar, people assume that kind of fore-thought is not worth the while. But reality has showed us that software maintenance is very expensive.

4

Having the variable constrained to an interface ensures none of the usages of that variable will be using HashMap specific functionality that may not exist on the interface, so the instance may be changed without concern later to a different implementation so long as the new instance also implements the interface.

For this reason, anytime you want to use an objects interface, it is always good practice to declare your variables as the interface and not the particular implementation, this goes for all types of objects you may use which have an interface. The reason you see it often is many people have built this in as a habit.

That said, it's not harmful to skip out of using interfaces sometimes, and most of us sloppily don't always follow this rule, with no real harm. It's just a good practice to stick to when you have any feeling the code may be changed and need maintenance/growth in the future. It's less of a concern when you're hacking on code you don't suspect will have a long life or has much importance. Also breaking this rule usually has a small consequence that changing the implementation to another one may require a bit of refactoring, so if you don't always follow it you won't hurt yourself a lot, though there's no real harm in following it either.

4

It's to follow the interface segregation principle (the 'I' in SOLID). It prevents code that uses those objects from depending on methods of those objects it doesn't need, which makes the code less coupled, and therefore easier to change.

For example, if you find out later you really need a LinkedHashMap, you can safely make that change without affecting any other code.

However, there's a trade off, because you're artificially limiting the code that can take your object as a parameter. Say there's a function somewhere that requires a HashMap for some reason. If you return a Map, you can't pass your object into that function. You have to balance the likelihood of sometime in the future needing the extra functionality that's in the more concrete class with the desire to limit coupling and keep your public interface as small as possible.

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.