(1) List<?> myList = new ArrayList<?>(); (2) ArrayList<?> myList = new ArrayList<?>();
I understand that with (1), implementations of the List interface can be swapped. It seems that (1) is typically used in an application regardless of need (myself I always use this).
I am wondering if anyone uses (2)?
Also, how often (and can I please get an example) does the situation actually require using (1) over (2) (i.e. where (2) wouldn't suffice..aside coding to interfaces and best practices etc.)
ArrayList class is used to create a dynamic array that contains objects. List interface creates a collection of elements that are stored in a sequence and they are identified and accessed using the index. ArrayList creates an array of objects where the array can grow dynamically.
One of the major differences is that List is an interface and ArrayList is a class of Java Collection framework. The List extends the collection framework, comparatively ArrayList extends AbstractList class and implements the List interface. The namespace for the List and ArrayList is System.
By declaring the listStrings variable to be of type List instead of ArrayList, your code is saying that it is more concerned with the contract of behavior as defined by the List interface rather than the implementation of that behavior as provided by the ArrayList class.
ArrayList clone() method is used to create a shallow copy of the list.
Almost always List
is preferred over ArrayList
because, for instance, List
can be translated into a LinkedList
without affecting the rest of the codebase.
If one used ArrayList
instead of List
, it's hard to change the ArrayList
implementation into a LinkedList
one because ArrayList
specific methods have been used in the codebase that would also require restructuring.
You can read about the List
implementations here.
You may start with an ArrayList
, but soon after discover that another implementation is the more appropriate choice.
I am wondering if anyone uses (2)?
Yes. But rarely for a sound reason (IMO).
And people get burned because they used ArrayList
when they should have used List
:
Utility methods like Collections.singletonList(...)
or Arrays.asList(...)
don't return an ArrayList
.
Methods in the List
API don't guarantee to return a list of the same type.
For example of someone getting burned, in https://stackoverflow.com/a/1481123/139985 the poster had problems with "slicing" because ArrayList.sublist(...)
doesn't return an ArrayList
... and he had designed his code to use ArrayList
as the type of all of his list variables. He ended up "solving" the problem by copying the sublist into a new ArrayList
.
The argument that you need to know how the List
behaves is largely addressed by using the RandomAccess
marker interface. Yes, it is a bit clunky, but the alternative is worse.
Also, how often does the situation actually require using (1) over (2) (i.e. where (2) wouldn't suffice..aside 'coding to interfaces' and best practices etc.)
The "how often" part of the question is objectively unanswerable.
(and can I please get an example)
Occasionally, the application may require that you use methods in the ArrayList
API that are not in the List
API. For example, ensureCapacity(int)
, trimToSize()
or removeRange(int, int)
. (And the last one will only arise if you have created a subtype of ArrayList that declares the method to be public
.)
That is the only sound reason for coding to the class rather than the interface, IMO.
(It is theoretically possible that you will get a slight improvement in performance ... under certain circumstances ... on some platforms ... but unless you really need that last 0.05%, it is not worth doing this. This is not a sound reason, IMO.)
You can’t write efficient code if you don’t know whether random access is efficient or not.
That is a valid point. However, Java provides better ways to deal with that; e.g.
public <T extends List & RandomAccess> void test(T list) { // do stuff }
If you call that with a list that does not implement RandomAccess
you will get a compilation error.
You could also test dynamically ... using instanceof
... if static typing is too awkward. And you could even write your code to use different algorithms (dynamically) depending on whether or not a list supported random access.
Note that ArrayList
is not the only list class that implements RandomAccess
. Others include CopyOnWriteList
, Stack
and Vector
.
I've seen people make the same argument about Serializable
(because List
doesn't implement it) ... but the approach above solves this problem too. (To the extent that it is solvable at all using runtime types. An ArrayList
will fail serialization if any element is not serializable.)
Finally, I'm not going to say "because its is good style". That "reason" is both a circular argument ("Why is it 'good style'?") and an appeal to an unstated (and probably non-existent!) higher authority ("Who says it is 'good style'?").
(I do think it is good style to program to the interface, but I'm not going to give that as a reason. It is better for you to understand the real reasons and come to the (IMO) correct conclusions for yourself. The correct conclusion may not always be the same ... depending on the context.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With