81

PMD would report a violation for:

ArrayList<Object> list = new ArrayList<Object>();

The violation was "Avoid using implementation types like 'ArrayList'; use the interface instead".

The following line would correct the violation:

List<Object> list = new ArrayList<Object>();

Why should the latter with List be used instead of ArrayList?

Cœur
  • 37,241
  • 25
  • 195
  • 267
jnancheta
  • 7,008
  • 8
  • 25
  • 18

10 Answers10

84

Using interfaces over concrete types is the key for good encapsulation and for loose coupling your code.

It's even a good idea to follow this practice when writing your own APIs. If you do, you'll find later that it's easier to add unit tests to your code (using Mocking techniques), and to change the underlying implementation if needed in the future.

Here's a good article on the subject.

Hope it helps!

dan1st
  • 12,568
  • 8
  • 34
  • 67
kolrie
  • 12,562
  • 14
  • 64
  • 98
  • 2
    And what about using "Collection" instead of "List", so we go one step further in abstraction...? – user1156544 May 23 '18 at 15:44
  • @user1156544 Would you abstract away some functionality allowed by the List interface (e.g. index based operations)? – CJay Horton May 24 '22 at 11:30
  • I would leave it up to the final implementation details. If `Collection` is used, changes from e.g. `Set` to `List` will be transparent for all intermediate classes except for the final one that does the implementation. If the caller needs specific features, then it can "use" the object as needed. – user1156544 May 30 '22 at 14:29
  • Hello, If you initialize the data structure referenced by 'list' as an ArrayList Class you will only be able to access the appended data with ArrayList Class methods. You cannot reinitialize 'list' as a new Class like LinkedList. The best way to get access to both ArrayList and LinkedList methods is to use an interface. – Luke Autry Jan 14 '23 at 12:42
33

This is preferred because you decouple your code from the implementation of the list. Using the interface lets you easily change the implementation, ArrayList in this case, to another list implementation without changing any of the rest of the code as long as it only uses methods defined in List.

AdamC
  • 16,087
  • 8
  • 51
  • 67
12

In general I agree that decoupling interface from implementation is a good thing and will make your code easier to maintain.

There are, however, exceptions that you must consider. Accessing objects through interfaces adds an additional layer of indirection that will make your code slower.

For interest I ran an experiment that generated ten billion sequential accesses to a 1 million length ArrayList. On my 2.4Ghz MacBook, accessing the ArrayList through a List interface took 2.10 seconds on average, when declaring it of type ArrayList it took on average 1.67 seconds.

If you are working with large lists, deep inside an inner loop or frequently called function, then this is something to consider.

Jason Plank
  • 2,336
  • 5
  • 31
  • 40
Owen
  • 2,759
  • 1
  • 14
  • 9
  • @Owen: +5 Insightful re: Performance Difference ... Very Unexpected – Ande Turner Nov 15 '08 at 06:39
  • 2
    This answer however shows that the overhead can be very small: http://stackoverflow.com/questions/890687/overhead-of-implementing-an-interface/891096#891096 – Raedwald Nov 01 '11 at 15:10
  • 6
    Wow! 0.5 seconds for ten billion accesses, i.e. 1 interface access is half a nanosecond slower than a class access! This is of course a reason to never, ever use interfaces. – Ingo Oct 12 '13 at 21:47
  • But if you have few hundreds such places in your code(and in big application it could be very easy) and your app is handling terrabytes of a data, then 0.5 nanosecond can be an one second – Nemo May 20 '23 at 15:29
6

ArrayList and LinkedList are two implementations of a List, which is an ordered collection of items. Logic-wise it doesn't matter if you use an ArrayList or a LinkedList, so you shouldn't constrain the type to be that.

This contrasts with say, Collection and List, which are different things (List implies sorting, Collection does not).

SCdF
  • 57,260
  • 24
  • 77
  • 113
2

Why should the latter with List be used instead of ArrayList?

It's a good practice : Program to interface rather than implementation

By replacing ArrayList with List, you can change List implementation in future as below depending on your business use case.

List<Object> list = new  LinkedList<Object>(); 
/* Doubly-linked list implementation of the List and Deque interfaces. 
 Implements all optional list operations, and permits all elements (including null).*/

OR

List<Object> list = new  CopyOnWriteArrayList<Object>(); 
/* A thread-safe variant of ArrayList in which all mutative operations
 (add, set, and so on) are implemented by making a fresh copy of the underlying array.*/

OR

List<Object> list = new  Stack<Object>(); 

/* The Stack class represents a last-in-first-out (LIFO) stack of objects.*/

OR

some other List specific implementation.

List interface defines contract and specific implementation of List can be changed. In this way, interface and implementation are loosely coupled.

Related SE question:

What does it mean to "program to an interface"?

Community
  • 1
  • 1
Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
1

In general for your line of code it does not make sense to bother with interfaces. But, if we are talking about APIs there is a really good reason. I got small class

class Counter {
    static int sizeOf(List<?> items) {
        return items.size();
    }
}

In this case is usage of interface required. Because I want to count size of every possible implementation including my own custom. class MyList extends AbstractList<String>....

Jason Plank
  • 2,336
  • 5
  • 31
  • 40
Rastislav Komara
  • 1,711
  • 8
  • 17
  • If you code to implementations like ArrayList, there is every possibility that you may use methods of implementation even when you could do the same thing with interface methods. This would bind your code to the implementation - making it harder to switch between implementations later. – Champ May 01 '11 at 08:37
1

Properties of your classes/interfaces should be exposed through interfaces because it gives your classes a contract of behavior to use, regardless of the implementation.

However...

In local variable declarations, it makes little sense to do this:

public void someMethod() {
List theList = new ArrayList();
//do stuff with the list
}

If its a local variable, just use the type. It is still implicitly upcastable to its appropriate interface, and your methods should hopefully accept the interface types for its arguments, but for local variables, it makes total sense to use the implementation type as a container, just in case you do need the implementation-specific functionality.

Jason Plank
  • 2,336
  • 5
  • 31
  • 40
MetroidFan2002
  • 29,217
  • 16
  • 62
  • 80
1

Even for local variables, using the interface over the concrete class helps. You may end up calling a method that is outside the interface and then it is difficult to change the implementation of the List if necessary. Also, it is best to use the least specific class or interface in a declaration. If element order does not matter, use a Collection instead of a List. That gives your code the maximum flexibility.

Diastrophism
  • 15,139
  • 1
  • 16
  • 7
0

Interface is exposed to the end user. One class can implement multiple interface. User who have expose to specific interface have access to some specific behavior which are defined in that particular interface.

One interface also have multiple implementation. Based on the scenario system will work with different scenario (Implementation of the interface).

let me know if you need more explanation.

0

The interface often has better representation in the debugger view than the concrete class.

Kiruahxh
  • 1,276
  • 13
  • 30