162

Possible Duplicate:
Why should the interface for a Java class be prefered?

When should I use

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

ArrayList inherits from List, so if some features in ArrayList aren't in List, then I will have lost some of the features of ArrayList, right? And the compiler will notice an error when trying to access these methods?

Community
  • 1
  • 1
hqt
  • 29,632
  • 51
  • 171
  • 250
  • Oh. I'm sorry. because I change to `object`, so I forget it. – hqt Mar 24 '12 at 15:44
  • 6
    @duffymo - That question is asking why `new List()` doesn't work. It's a completely different question. – Brendan Long Mar 24 '12 at 18:18
  • 2
    Its not a duplicate question. The possible duplicate has generic question but a specific detail. I find this question in title is more relevant/in sync to whats actually asked. – Dexters May 26 '13 at 20:31
  • Just one more doubt guyz: "List list = new ArrayList();" will allow you to access only List interface's functions in Arraylist (so we can't use Arraylist functions). "List list = new LinkedList();" will allow you to access only List interface's functions in Linkedlist (so we can't use LinkedList functions). Aren't then both same? Or is it just the 'time complexity' where the difference comes in? – Vyshnav Ramesh Thrissur Jan 19 '18 at 03:09
  • Use `Iterable` if you can in general. Basically, you want to use the most restricted, narrow type as possible to document the usage of your variable before it has ever been used. It's simply more understandable. That's the main reason. – user904963 Nov 06 '21 at 10:48

8 Answers8

275

The main reason you'd do this is to decouple your code from a specific implementation of the interface. When you write your code like this:

List list = new ArrayList();  

the rest of your code only knows that data is of type List, which is preferable because it allows you to switch between different implementations of the List interface with ease.

For instance, say you were writing a fairly large 3rd party library, and say that you decided to implement the core of your library with a LinkedList. If your library relies heavily on accessing elements in these lists, then eventually you'll find that you've made a poor design decision; you'll realize that you should have used an ArrayList (which gives O(1) access time) instead of a LinkedList (which gives O(n) access time). Assuming you have been programming to an interface, making such a change is easy. You would simply change the instance of List from,

List list = new LinkedList();

to

List list = new ArrayList();  

and you know that this will work because you have written your code to follow the contract provided by the List interface.

On the other hand, if you had implemented the core of your library using LinkedList list = new LinkedList(), making such a change wouldn't be as easy, as there is no guarantee that the rest of your code doesn't make use of methods specific to the LinkedList class.

All in all, the choice is simply a matter of design... but this kind of design is very important (especially when working on large projects), as it will allow you to make implementation-specific changes later without breaking existing code.

Matt
  • 74,352
  • 26
  • 153
  • 180
Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
  • 60
    A lot of people fail to mention it's perfectly acceptable to instantiate it as a local variable via ArrayList list = new ArrayList(). It's only really beneficial to use the List interface in the method signature or as the type of a class level variable. Who cares if you have to go back later and change the local method declaration? The whole benefit comes when exposing a List to other methods or libraries, etc. – GreenieMeanie Mar 29 '12 at 16:28
  • 6
    That's true, thanks for pointing that out. In fact, now that I think about it, it probably would have made more sense for me to give an example from the standpoint of a client, rather than the programmer himself. In both cases, using `List list = new ArrayList()` is a matter of ensuring that you don't break existing code. – Alex Lockwood Apr 01 '12 at 17:05
  • Whose methods are available by this casting? list or arraylist? – Zahan Safallwa Feb 27 '16 at 13:58
  • 1
    @Zahan Safallwa the methods of List,or you may access the methods of ArrayList by downcasting later – LancelotHolmes Nov 21 '16 at 03:11
  • 1
    What you say about `list.removeRange();` of ArrayList ? it forced me to cast list to ArrayList to use. Same as some methods for LinkedList. – Asif Mushtaq Dec 17 '16 at 17:13
  • 2
    Doesn't doing `List al = new ArrayList()` make you lose out on some ArrayList features that may have been used with `al`? – rahs Sep 15 '18 at 17:27
  • 1
    Is it premature optimization, as I have worked with various projects and never ever changed my list to ArrayList to any other ? – Raj Saraogi Jul 22 '21 at 11:50
73

This is called programming to interface. This will be helpful in case if you wish to move to some other implementation of List in the future. If you want some methods in ArrayList then you would need to program to the implementation that is ArrayList a = new ArrayList().

Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
tsatiz
  • 1,081
  • 7
  • 18
27

This is also helpful when exposing a public interface. If you have a method like this,

public ArrayList getList();

Then you decide to change it to,

public LinkedList getList();

Anyone who was doing ArrayList list = yourClass.getList() will need to change their code. On the other hand, if you do,

public List getList();

Changing the implementation doesn't change anything for the users of your API.

Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
Brendan Long
  • 53,280
  • 21
  • 146
  • 188
10

I think @tsatiz's answer is mostly right (programming to an interface rather than an implementation). However, by programming to the interface you won't lose any functionality. Let me explain.

If you declare your variable as a List<type> list = new ArrayList<type> you do not actually lose any functionality of the ArrayList. All you need to do is to cast your list down to an ArrayList. Here's an example:

List<String> list = new ArrayList<String>();
((ArrayList<String>) list).ensureCapacity(19);

Ultimately I think tsatiz is correct as once you cast to an ArrayList you're no longer coding to an interface. However, it's still a good practice to initially code to an interface and, if it later becomes necessary, code to an implementation if you must.

Hope that helps!

SecondSun24
  • 492
  • 5
  • 12
  • 4
    I really don't like this answer. If you are using ArrayList methods then you should define it as an ArrayList. If someone went to change the list implementation they would be surprised at the compilation failure for sure. – Gray Jun 21 '18 at 18:05
  • Doing as the answer suggests is technically fine if a bit sloppy looking, as the knowledge that the List is an ArrayList is local to the function and obvious from the previous line. However, it would be a poor choice to return the ArrayList as a List and do the casting in another function, as this would violate the entire point of programming to interface. – sleepysilverdoor Feb 20 '19 at 11:44
7

This enables you to write something like:

void doSomething() {
    List<String>list = new ArrayList<String>();
    //do something
}

Later on, you might want to change it to:

void doSomething() {
    List<String>list = new LinkedList<String>();
    //do something
}

without having to change the rest of the method.

However, if you want to use a CopyOnWriteArrayList for example, you would need to declare it as such, and not as a List if you wanted to use its extra methods (addIfAbsent for example):

void doSomething() {
    CopyOnWriteArrayList<String>list = new CopyOnWriteArrayList<String>();
    //do something, for example:
    list.addIfAbsent("abc");
}
assylias
  • 321,522
  • 82
  • 660
  • 783
  • 1
    As per the accepted answer's @GreenieMeanie comment, this change doesn't matter since this is a local variable. – RamValli Jan 07 '16 at 09:37
6

I guess the core of your question is why to program to an interface, not to an implementation

Simply because an interface gives you more abstraction, and makes the code more flexible and resilient to changes, because you can use different implementations of the same interface(in this case you may want to change your List implementation to a linkedList instead of an ArrayList ) without changing its client.

Mouna Cheikhna
  • 38,870
  • 10
  • 48
  • 69
5

I use that construction whenever I don't want to add complexity to the problem. It's just a list, no need to say what kind of List it is, as it doesn't matter to the problem. I often use Collection for most of my solutions, as, in the end, most of the times, for the rest of the software, what really matters is the content it holds, and I don't want to add new objects to the Collection.

Futhermore, you use that construction when you think that you may want to change the implemenation of list you are using. Let's say you were using the construction with an ArrayList, and your problem wasn't thread safe. Now, you want to make it thread safe, and for part of your solution, you change to use a Vector, for example. As for the other uses of that list won't matter if it's a AraryList or a Vector, just a List, no new modifications will be needed.

SHiRKiT
  • 1,024
  • 3
  • 11
  • 30
2

In general you want to program against an interface. This allows you to exchange the implementation at any time. This is very useful especially when you get passed an implementation you don't know.

However, there are certain situations where you prefer to use the concrete implementation. For example when serialize in GWT.

stefan bachert
  • 9,413
  • 4
  • 33
  • 40