14

What is the difference in declaring a collection as such

public class CatHerder{
    private List cats;
    public CatHerder(){
        this.cats = new ArrayList<Cat>();
    }
}
//or
public class CatHerder{
    private ArrayList cats;
    public CatHerder(){
        this.cats = new ArrayList();
    }
}
//or
public class CatHerder{
    private ArrayList<Cat> cats;
    public CatHerder(){
        this.cats = new ArrayList<Cat>();
    }
}
davidahines
  • 3,976
  • 16
  • 53
  • 87

6 Answers6

26

You should declare it as a List<Cat>, and initialize it as an ArrayList<Cat>.

List is an interface, and ArrayList is an implementing class. It's almost always preferable to code against the interface and not the implementation. This way, if you need to change the implementation later, it won't break consumers who code against the interface.

Depending on how you actually use the list, you might even be able to use the less-specific java.util.Collection (an interface which List extends).

As for List<Cat> (you can read that as "list of cat") vs List: that's Java's generics, which ensure compile-time type safely. In short, it lets the compiler make sure that the List only contains Cat objects.


public class CatHerder{
    private final List<Cat> cats;
    public CatHerder(){
        this.cats = new ArrayList<Cat>();
    }
}
Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • I've seen this argument being used many times before. But in what circumstance would you actually see it being necessary to declare the interface type? Is there a use case where one would initialize a specific collection type, add data to it and then a bit later change his mind about the collection type? – Evil Washing Machine Nov 26 '14 at 13:06
  • 1
    @EvilWashingMachine http://programmers.stackexchange.com/q/225674/1845 and http://stackoverflow.com/a/505148/139010 – Matt Ball Nov 26 '14 at 17:46
4

I would do the following.

public class CatHerder{
    private final List<Cat> cats = new ArrayList<Cat>();
}
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 1
    6 years later, assuming java 7+ I prefer to initialize with List cats = new ArrayList<>();. I picked this up from the eclipse sonar plugin. Quoting Sonar rule id 2293, "Java 7 introduced the diamond operator (<>) to reduce the verbosity of generics code. For instance, instead of having to declare a List's type in both its declaration and its constructor, you can now simplify the constructor declaration with <>, and the compiler will infer the type." – kyle Sep 07 '17 at 22:06
2

In order to ensure type safety, and because current Java compilers will complain if a generic type has no type argument, you should always specify a type explicitly - or <?> if you really don't care.

That said, unless you use something specific to the ArrayList class, you should use List<Cat> to avoid tying your code to a particular List implementation.

thkala
  • 84,049
  • 23
  • 157
  • 201
1

As Matt already stated, using the most common Interface/Superclass is the best way to go here. Make sure to always declare the Type that appears in your List, so make it a List<Cat> or even List<? extends Cat>

If, at some later point, you want to replace the ArrayList with, say, a LinkedList, you won't have to change the declaration, but only the instantiation.

f1sh
  • 11,489
  • 3
  • 25
  • 51
1

List is more flexible than ArrayList, List<Cat> is safer than List. so List<Cat> is good choice.

卢声远 Shengyuan Lu
  • 31,208
  • 22
  • 85
  • 130
1

First of all, List is an interface and ArrayList is an implementation of the List interface (actually, it subclasses AbstractList and implements List). Therefore List cats = new ArrayList() is valid since ArrayList is-a List.

For this:

private List cats;

cats becomes a raw-type (there is no reference to the Generic Type for List), it hasn't been parameterised.

Your 3rd solution is correct (it solves your problem for option 1),

private ArrayList<Cat> cats;

you have bounded a Generic Type E for List<E> to a type Cat. Therefore, your instantiation of cats is valid as the generic bounding is the same.

Your 2nd solution allows that only ArrayList of cats can be instantiated. The other 2 options allows you to instantiate any object that is-a List, e.g. LinkedList.

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228