5

Assuming you have a class something like:

public class foo {
    private List<String> fooThings;

    public void doSomething(List<String> things) {
        // Do a bunch of things here
        // Possibly setting fooThings at some point as well
    }
}

Is it ever appropriate for declarations to specify the concrete class e.g. ArrayList instead of the List interface? If so, when?

Edit> This question has nothing to do with when to use a LinkedList and when to use an ArrayList. That is a separate question that is answered elsewhere. The question is about when declarations should be the interface (List) for clarity and when it should specify an implementation e.g. ArrayList because it matters given what the method is going to do or how the instance variable will be leveraged.

Eric98118
  • 397
  • 3
  • 15
  • 10
    When you want to use methods available only in that implementation (Something like these http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#trimToSize()). – kosa Sep 24 '13 at 20:34
  • 2
    See all the related answers on the right. – Sotirios Delimanolis Sep 24 '13 at 20:35
  • @Sotirios Delimanolis - All those related answers that are asking a totally different question? – Eric98118 Sep 24 '13 at 20:37
  • @Eric98118 The question might be different, but the answer will be the same. Although you are asking for `ArrayList` and `LinkedList` specifically, the answer pretty much covers every implementation type. – Sotirios Delimanolis Sep 24 '13 at 20:39
  • Certainly it's "correct" to do so, when you know which you will use and have no intention of making the code "generic". It's advantageous to do this when you will be using methods specific to the subclass, but not so useful if (after object construction) you will be using only methods belonging to the superclass/interface. (Of course, "correct" and "politically correct" are two different things.) – Hot Licks Sep 24 '13 at 20:42
  • 1
    @Nambari considering the current answers, you might want to write another one... – assylias Sep 24 '13 at 20:48
  • @assylias: I would like to, but, due to time constraints & work pressure I am limiting myself to comments now a days (unless I can finish answer in one/two sentences). – kosa Sep 24 '13 at 20:51
  • @Bathsheba please undelete your answer! – Alnitak Sep 24 '13 at 20:57
  • 1
    @Nambari I know the feeling... – assylias Sep 24 '13 at 20:57

7 Answers7

3

Normally you should only use the interface List to declare your structure. However, on the rare occasion you need to use a specific method that is only available for a certain implementation of List such as LinkedList or ArrayList then you should declare your list type explicitly. However, this limits flexibility and should be done sparingly.

JNYRanger
  • 6,829
  • 12
  • 53
  • 81
1

This is not an example of ArrayList/LinkedList, but I think a method returning a List might be good to declare like this:

public ImmutableList doSomething();

where ImmutableList is Guava's ImmutableList. This kind of declaration makes clear that the returned list is not intended to be modified, so it is communicated by the code rather than comments (or only exceptions during runtime on attempt to modify the list).

Katona
  • 4,816
  • 23
  • 27
1

The simple answer is when you want to define for your users what performance they can expect.

Essentially, if all you are working with is a List and it doesn't really matter what kind of list it is, say you just intend to iterate across it then declare it as a List.

If, however, you want to do specific things to the list like inserting entries or getting the nth entry a lot then it makes sense to let everyone know what kind of list it is and thus the performance expectation.

OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
  • 1
    IMHO you shouldn't constrain a function to use a specific implementation of `List` just because it has a particular usage pattern within. That's what Javadoc is for, and the caller may be prepared to take that performance hit. – Alnitak Sep 24 '13 at 20:55
  • 1
    If you just intend to iterate across declare it as Iterable rather than list. Then you can use List, Set, Collection and other types. I strongly disagree with your point of view that type has something with performance. – Damian Leszczyński - Vash Sep 24 '13 at 21:12
  • @Alnitak - Good points - but OP asked *When is it correct ...*. Never is a long time. – OldCurmudgeon Sep 24 '13 at 21:48
  • @Vash - Exactly my point. If just iterating then who cares! It's when **performance** needs to be exposed, then and only then should you expose the underlying structure. The only difference between `ArrayList` and `LinkedList` (apart from the twiddly bits) is performance. – OldCurmudgeon Sep 24 '13 at 21:52
1

It is a good practice to use abstract type as method argument or field declaration.

This gives your code the possibility to work in the way that you do not imagine yet.

As we are in the Collection framework i write some advice that i use while coding.

If i do not need to know the size off bag i used Iterable interface. This allow me to use the foreach and i can pass various types later that are not from java collection framework.

If i need the size of bag i use the collection interface.

If i need to pick items from bag i use List interface.

When i need to operate on unique items i use Set interface.

Generally i start with iterable later i change it to other type but those are few exeptions rather than a rule.

1

You might want to assure a certain property of the list which is not granted by the List-Interface. In the following example you might pass in a List which is not Seralizable, leading to a Runtime-Error when the class is serialized. :

public class foo implements Serializable{

private List<String> fooThings;

public void setFooThings(List<String> things) {
   fooThings = things;
}

}

ArrayList implements Serializable. There are other ways to make sure the list is Seralizable through Generic Methods, for example

public <T extends List & Serializable> setFooThings(T things) 
0

You always want to declare the variable as:

private List<String> fooThings;

This allows us to use any type of list, LinkedList, ArrayList, etc when we are actually using fooThings.

It is possible that you may use a LinkedList in some parts of the program, and then switch to an ArrayList for another part because it is a better fit. We want to allow ourselves the maximum flexibility while developing.

We could also run into the case where fooThings is initialized via a parameter coming from another class. We do not want to declare this as a specific type of list, because then we limit the callers of our method to using this specific type of list, or convert their list type to the correct type before using our method which causes unnecessary work.

Hampton Terry
  • 344
  • 1
  • 13
  • Is this ever impacted by performance concerns, similar to the answer from OldCurmudgeon? For example, method willAddFiftyGazillionNewObjectsToYourCollectionOneAtATimeMethod(List fooThings)? – Eric98118 Sep 24 '13 at 21:06
  • Note: That seems like a pretty terrible method, just trying to understand if performance concerns are a valid reason for constraining the requirement down to a specific implementation vs the interface. – Eric98118 Sep 24 '13 at 21:09
0

It's always good to write to interface not to implementation. This will give flexibility to handle different concerete types which implements passed interface..

One more abstaract level your example code is

public class foo {
    private Collection<String> fooThings;

    public void doSomething(Collection<String> things) {
        // Do a bunch of things here
        // Possibly setting fooThings at some point as well
    }
}

Advantage - This will allow you to process different concerete types of input.

Disadvantage - It will restrict want to use any specific functionality of concerete type. E.g. you may not able to use getFirst() which is specific for the LinkedList.

Code to interface - flexible/loosely couple code. Code to implementation - for special operation.

neo
  • 1,054
  • 1
  • 10
  • 19