9

Can any one explain what is the difference in the following declaration of ArrayList to store String.

List type1 = new ArrayList();
List type2 = new ArrayList<String>();
List<String> type3 = new ArrayList<String>();
ArrayList<String> type4 = new ArrayList<String>();
List<String> type5 = null;
ArrayList<String> type6 = null;

so which of the above declaration is best practice to declare an ArrayList of String and why?

Maroun
  • 94,125
  • 30
  • 188
  • 241
Naveen
  • 1,284
  • 4
  • 13
  • 20
  • Also see [*"What's the difference between these ways of initializing a HashMap?"*](http://stackoverflow.com/q/26565606/2891664) – Radiodef Apr 20 '15 at 05:02

6 Answers6

10

The first two use raw types. Doing that means your list isn't type-safe at all. The compiler will let you store Integers inside even if your intention is to have a list of strings. The compiler will emit a warning, that you should not ignore.

The third one is right. It tells the compiler that your intention is to use a List of strings, and that the specific implementation you chose is ArrayList. If you change your mind later and want to use a LinkedList, this line of code is the only one you need to change.

The fourth one tells the compiler that your program doest't just need a List. It needs this List to be an ArrayList. This is OK if your code indeed needs to call methods that are specific to ArrayList, and are not present in the List interface. But in 99.9% of the cases, that's not the case and you should prefer the third one.

The two last ones declare a variable and initialize it to null instead of creating a list. That is a design smell. You'll have to make sure everywhere, before using the list, that it's not null. It's much safer to initialize it with a valid list right away.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
7
  • List type1 = new ArrayList();
  • List type2 = new ArrayList<String>();

    You have a raw type ArrayList and List, you shouldn't use them (though it's legal code):

    ... The term "unchecked" means that the compiler does not have enough type information to perform all type checks necessary to ensure type safety

  • List<String> type3 = new ArrayList<String>();

    This one is safe, and since Java 7 it could use the diamond operator and rewritten as:

    List<String> type3 = new ArrayList<>();

    It's the best since it's program to an interface, meaning that you can change type3 to any other class that implements List.

  • ArrayList<String> type4 = new ArrayList<String>();

    This one is a specific object, you can never change the type of type4 to something else rather than ArrayList.

The last two cannot be compared to the rest, you're simply giving them a default value, sometimes you're forced to, sometimes you can skip this initialization.

Maroun
  • 94,125
  • 30
  • 188
  • 241
2

type1 and type2 are Raw Types and should be avoided.

type3 and type4 are good (but not IMO the best, and I will get back to that) - I would prefer type3 to type4 because it uses the interface type (and you should program to the interface). You might, for example, use an Arrays.asList("a","b") with type3.

type5 and type6 are similar to type3 and type4 but I would recommend you avoid initializing to null.

Finally, with Java 7+ I would recommend the diamond operator. For example,

List<String> type7 = new ArrayList<>();
Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
2

In general, it's good practice to keep the left hand side the least-specific type that you need to perform your functionality. However, you should always parameterize parameterizable types and avoid raw types. So you should use:

List<String> type3 = new ArrayList<String>();

Note that as of Java 7, you can also omit the type on the right-side:

List<String> type3 = new ArrayList<>();

Later on, should you want to use a LinkedList instead, you can simply update the line of code where you create the list, without having to change all references to it.

Oleg Vaskevich
  • 12,444
  • 6
  • 63
  • 80
2
  • 1 and 2 are raw type declarations. You will be able to add any object type into this list that you like, but you will not be able to guarantee type safety at compile time.

    Declaring a list in this manner is generally frowned upon, as it can be a very simple mistake to accidentally put an object into the list that you shouldn't have. The real caveat here is that this mistake won't manifest itself until runtime, whereas using a type parameter will have this error manifest itself at compile time, which is far easier to deal with.

  • 3 is the preferred approach to declaring a list (or collection of any kind), as you're bound to the interface instead of the concrete implementation. It also includes the type bounds, which guarantees compile-time type safety.

  • 4 is a declaration to the concrete type ArrayList. If you required the concrete type, then this is OK, but there are vanishingly few cases in which you do.

  • 5 and 6 are repeats of 3 and 4, respectively; the difference being that they are both initialized to null.

Community
  • 1
  • 1
Makoto
  • 104,088
  • 27
  • 192
  • 230
1

Either List<String> type3 = new ArrayList<String>(); or List<String> type5 = null;.

It's always better not to use raw types such as List and ArrayList, and it's more flexible to declare variables of interface types instead of implementation types.

As to whether you want to initialize the variable to null and instantiate the List later (or assign to the variable the result of a method that returns a List instance), or to instantiate it when you declare it, both options are equally valid in my opinion.

Eran
  • 387,369
  • 54
  • 702
  • 768