John
John

Reputation: 1189

Use interface or type for variable definition in java?

ArrayList aList = new ArrayList();

List aList = new ArrayList();

What's the difference between these two and which is better to use and why?

Upvotes: 18

Views: 5188

Answers (8)

Nils von Barth
Nils von Barth

Reputation: 3429

This is a Java quirk, due to limited type inference and doctrine OOP. For local variables it's mostly style; if you need some specific feature of the subtype, use the subtype (examples below), but otherwise fine to use either.

Java style is to use the supertype, to enforce interfaces even within the body of implementations, and for consistency with visible types (Effective Java 2nd Edition: Item 52: Refer to objects by their interfaces). In languages with more type inference, such as C++/C#/Go/etc., you don't need to explicitly state the type, and the local variable will have the specific type.

For visible types (public or protected: fields, or parameters and return value of methods), you almost always want to use the most general type: interface or abstract class, to provide better flexibility (Effective Java: Item 40: Design method signatures carefully). However, for types that are not visible (private or package-private members, or local variables), it's ok to use either (it's just style) and sometimes necessary to use more specific types, including concrete classes.

See Effective Java for standard guidelines; personal thoughts follow.

The reason to use more general types even if not visible is to reduce noise: you're stating that you only need the more general type. Using general types on members that are not visible (like private methods) also reduces churn if you ever change types. However, this doesn't apply to local variables, where it's just changing one line anyway: ConcreteFoo foo = new ConcreteFoo(); to OtherConcreteFoo foo = new OtherConcreteFoo();.

Cases where you do need the subtype include:

  • You need members only present on the subtype, e.g.:
    • some feature of the implementation, like ensureCapacity for ArrayList<T>
    • (common in test code) some member of a fake class, like (hypothetically) FakeFileSystem#createFakeFile.
  • You rely on the behavior of the subtype, notably in overrides of the supertype's methods, like:
    • having a more general type of parameter,
    • more specific return type, or
    • throwing a more specific or fewer exception types.

As an example of the last, see Should I close a StringReader?: StringReader.html#close overrides Reader.html#close and does not throw an IOException, so using StringReader instead of Reader for the local variable means you don't need to handle an exception that can't actually occur, and significantly reduces boilerplate.

Upvotes: 1

Michał Niklas
Michał Niklas

Reputation: 54302

List<T> is interface, where ArrayList<T> is class, and this class implements List<T> interface.

I would prefer 2nd form, which is more general, ie if you do not use methods specific to ArrayList<T> you can declare its type as interface List<T> type. With 2nd form it will be easier to change implementation from ArrayList<T> to other class that implements List<T> interface.

EDIT: As many of SO users commented both forms can be arguments to any method that accept List<T> or ArrrayList<T>. But when I declare method I would prefer interface:

 void showAll(List <String> sl) ...

and use:

 void showAllAS(ArrayList <String> sl) ...

only when my method uses method specific to ArrayList<T>, like ensureCapacity().

Response with information that we should use typed List<T> instead of just List is very good (of course if we do not use ancient Java).

Upvotes: 5

irreputable
irreputable

Reputation: 45443

All these answers are the same recite from some dogma they read somewhere.

A variable declaration and initialization statement, Type x = new Constructor();, is definitely part of implementation detail. It's not part of a public API (unless it's public final, but List is mutable so that's inappropriate)

As an implementation detail, who you are trying to fool with your abstractions? It's better to keep the type as specific as possible. Is it an array list or a linked list? Should it be thread safe or not? The choice is important for your implementation, you carefully chose the specific list impl. Then you declare it as a mere List as if it doesn't matter and you don't care?

The only legitimate reason to declare it as List is I'm too lazy to type. That also covers the argument that if I need to move to another List impl I have one less place to modify.

This reason is legitimate only when the variable scope is small, and you can see all of its usages from one glance. Otherwise, keep the most specific type, so that its performance and semantic characteristics are manifest across all the code that use the variable.

Upvotes: 2

BigMac66
BigMac66

Reputation: 1538

I know of at least one case when declaring a variable with an interface does not work. When you want to use reflection.

I made a bug fix on some code where I declared a variable as Map<String, MyObject> and assigned it an instance of HashMap<String, MyObject>. This variable was used as a parameter in a method call that was accessed via reflection. The problem is that reflection tried to find a method with HashMap signature and not the declared Map signature. Since there was no method with a HashMap as a parameter I was unable to find a method by reflection.

Map<String, Object> map = new HashMap<String, Object>();

public void test(Map<String, Object> m) {...};

Method m = this.getClass().getMethod("test", new Class<?>[]{map.getClass()});

Will not find the method that uses the interface. If you make another version of test that uses HashMap instead then it will work - but now you are forced to declare your variable with a concrete class and not the more flexible interface...

Upvotes: 0

bakoyaro
bakoyaro

Reputation: 2558

If you are using Java 1.4 or earlier, then I would use the second one. It's always better to declare your fields as generically as possible, in case you need to make it into something else later on, like a Vector, etc.

Since 1.5 I would go with the following

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

It gives you a little bit of type safety. List 'x' can add a String Object, and that's it. When you get an item from the List 'x', you can count on the fact that a String is going to come back. This also helps by removing unnecessary casting, which can make code hard to read when you go back 6 months later and try to remember what your code does. Your compiler/IDE will help you to remember what type should be going in to List 'x' by displaying an error if you try to add any other Object type.

If you want to add multiple Object types to a List then you could add an Annotation to suppress the compile error

@SuppressWarnings("unchecked")
List y = new ArrayList();

Upvotes: 0

Sean Patrick Floyd
Sean Patrick Floyd

Reputation: 298908

Both are deprecated since Java 1.5.

It should be:

List<String> list = new ArrayList<String>();
// or whatever data type you are using in your list

Please read Effective Java by Joshua Bloch, especially these two items:

  • 23: Don't use raw types in new code (this is even available online)
  • 52: Refer to objects by their interfaces

BTW, if you use Guava, you have a factory method for constructing an ArrayList so you don't have to repeat the type parameter:

List<String> list = Lists.newArraylist();

Upvotes: 7

Paul Tomblin
Paul Tomblin

Reputation: 182782

I prefer the second in most cases because it signifies that you're not using anything specific in the ArrayList api, and if you need to later you can substitute any other type of List without having to change any code except the first line.

Upvotes: 1

Rich
Rich

Reputation: 15767

List is an Interface, whereas ArrayList is an implementation of that interface.

The second is better because it means you can change your ArrayList for another implementation of List later without needing to change the rest of your application. You may want to do this for performance reasons, or because of other aspects of the behaviour of the List implementation that you have chosen/will choose.

Upvotes: 22

Related Questions