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?
Best Answer
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 usingHashMap
when you decide you need to useLinkedHashMap
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 aLinkedHashMap
to be passed, or better stillSortedMap
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 overrideSortedMap
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
andCat
which derive fromAnimal
, in order to make best use of inheritance, you should generally avoid having methods specific toDog
orCat
. Rather all methods inDog
orCat
should override methods inAnimal
and it will save you trouble in the long run.