The main difference is that in the first you are saying that the type of l1
is the interface List<T>
, whereas in the second case, the type of l2
is the concrete implementation (of List<T>
) ArrayList<T>
.
I would use the first form:
List<String> l1 = new ArrayList<String>();
Type using interfaces so that you can switch implementations easily later. The second implementation is tightly coupled to the ArrayList
implementation of List
. So if you wanted to change implementations later (say to LinkedList<T>
for example), you would have a lot of refactoring to do (changing method signatures, etc.). However if you used the first approach, you can simply swap out the implementation without having to do any additional refactoring.
Using the interface also forces you to code against the contract of the interface than any particular concrete-implementation.