• Post Reply Bookmark Topic Watch Topic
  • New Topic

List<?> or ArrayList<?> as a reference type?  RSS feed

 
Werner Holt
Ranch Hand
Posts: 37
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello all! I have been reeding a lot for this in the internet, but I still don't undertand one thing.
Everyone is saying that it is better practice to use (1) instead of (2), because it gives more flexibility.
With the knowledge I have I agree that (1) would be a better decision if it's a part from a method signature, thus the method will accept everything that implements the List interface, so it doesn't have to be only ArrayList.
But when we want to create an ArrayList like i did bellow, I don't see the point of using List as a reference type, because this mean we won't be able to use all the methods from the ArrayList class. So how is this better?


1.
2.
 
Jeanne Boyarsky
author & internet detective
Marshal
Posts: 37513
554
Eclipse IDE Java VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
What method is in the ArrayList class that isn't in List? List is an extremely thorough interface.
 
Werner Holt
Ranch Hand
Posts: 37
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Jeanne Boyarsky wrote:What method is in the ArrayList class that isn't in List? List is an extremely thorough interface.

ensureCapacity and few more.
 
Tim Holloway
Saloon Keeper
Posts: 18800
74
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
ArrayList implements the List interface. But as long as you need only the methods defined in java.util.List, it's certainly more flexible to use List. For example, you might decide later that a LinkedList would be a better choice.

ArrayLists can only expand by creating a new and larger array, then copying the old array into it. That can potentially be a lot of overhead. A LinkedList, on the other hand, never needs to do that.

If you had hard-coded ArrayList references everywhere, you'd have to change them everywhere. There are other implementations of List as well, such as the Stack.
 
Knute Snortum
Sheriff
Posts: 4289
127
Chrome Eclipse IDE Java Postgres Database VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
But when we want to create an ArrayList like i did bellow, I don't see the point of using List as a reference type, because this mean we won't be able to use all the methods from the ArrayList class. So how is this better?


If you absolutely need a method that is only in ArrayList, then use it. But avoid this methods if possible; they lock your code into a specific implementation.
 
Marcus Biel
Ranch Hand
Posts: 51
IntelliJ IDE Mac OS X Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If you don't need any specific ArrayList only method, you should ("MUST") use the broadest possible interface, which might be java.util.List<E>, but also java.util.Collection<E> might be sufficient.
If you need a specific method only the ArrayList implementation provides, you MIGHT have to use ArrayList - but make sure you REALLY have to - often it might be possible without.
If you really have to use the ArrayList reference, try to limit it's use as much as possible, which means encapsulate this reference. E.g. a client might just need a "E next()" method,
without even seeing the collection your class operates on. Always encapsulate as much as possible. If your client does not need to use the list, don't expose it at all.
Funny enough, by coicidence I have just done a little beginner java tutorial about interfaces, which might be interesting to you:
Interfaces in Java
 
Jeanne Boyarsky
author & internet detective
Marshal
Posts: 37513
554
Eclipse IDE Java VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Knute Snortum wrote:
But when we want to create an ArrayList like i did bellow, I don't see the point of using List as a reference type, because this mean we won't be able to use all the methods from the ArrayList class. So how is this better?


If you absolutely need a method that is only in ArrayList, then use it. But avoid this methods if possible; they lock your code into a specific implementation.

Agreed! And those methods are rarely needed to boot! ArrayList dynamically expands. I've never needed to ensure capacity.
 
Campbell Ritchie
Marshal
Posts: 56600
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You might need to increase capacity in advance of you are going to add large numbers of references to the List. Large numbers means millions.
There is also trimToSize.
Both should have been included in the List interface and they could not now be add to List as default methods.

[edit]Correctmisspelling not/now[/edit]
 
Tim Holloway
Saloon Keeper
Posts: 18800
74
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
ArrayList is based on storing the members in a fixed array of slots and the resizing methods adjust the number of available slots not the number of items in the list.

But not all Lists are architected that way. LinkedList doesn't have any reserved slots. Instead each link refers to its neighbors. So resizing methods wouldn't make sense there.

That's why those methods are not defined in the List interface.

You could also do other architectures, such as linked blocks of fixed slots (sort of a cross between ArrayList and LinkedList) and that, too could honor the List interface. Or get even more creative and make a fast-access list where you have an entire b-tree hierarchy of slots, giving much of the benefits of fast add/remove functions that LinkedLists have plus the fast random access that ArrayList has.
 
Campbell Ritchie
Marshal
Posts: 56600
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
In which case the default ensureCapacity method would do nothing; you would have to override it in ArrayList.
 
Tim Holloway
Saloon Keeper
Posts: 18800
74
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
But ensureCapacity makes assumptions about implementation and ideally, interfaces do not. A capacity method makes sense for a linear array of fixed slots, but what about a sparse array? Nothing in the concept of an abstract List says that the list has to have a fixed size or capacity.
 
Campbell Ritchie
Marshal
Posts: 56600
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
All ensure capacity does is to align the capacity with the expected size. Since linked lists never have a defined capacity, their capacity can never be different from what is required.
 
Tim Holloway
Saloon Keeper
Posts: 18800
74
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I hope we haven't lost the original concept of this thread, but:


Increases the capacity of this ArrayList instance, if necessary, to ensure that it can hold at least the number of elements specified by the minimum capacity argument.


This is very much an implementation method and not an abstract interface method. Normally an ArrayList ensures capacity in the same way the StringBuffer/Builder classes do. That is, if additional entry space is needed, a new array is allocated that's double the size of the former one.

The ensureCapacity method provides a (gag) pro-active (hate that word) alternative. If I know I'm going to need 1500 slots and the initial size was 32, then I'd be doubling and re-doubling the capacity repeatedly, requiring multiple allocations and copies. The ensureCapacity method simply says "allocate a backing array that has 1500 slots". That's also better than the case where you already have 1200 slots and you know you'll only need 300 more.

But it assumes that List is at least in some instances going to be one of a very a very specific architecture while ignoring the fact that there are many, many other cases where it doesn't apply or that it doesn't reflect the needs of some other radically different implementation. For example, take my hypothetical chunk-based "bTree" array list. I used the term b-tree sloppily, since you could just as easily be using n-tuples for the upper levels. In that case, an "ensureCapacity method, if implemented, might prefer to define the number of slots in the chunks and/or the allowed number of levels and/or the number of slots to compute levels for, and/or expansion space if you're doing sparse support and/or... No longer just a simple linear value. And that's not even counting things like using hashes or other non-array constructs to help implement the list in question. And, incidentally, in the case of hashes, the "capacity" value in the single-argument constructor doesn't refer to the total capacity, but only to the number of base hashtable slots.

In short, ensureCapacity is too specific for the abstract concept of a List, which means that it isn't appropriate as an Interface method. For that, you'd either want to subclass the interface to a more specific concept of fixed-slot lists or subclass ArrayList.
 
Don't get me started about those stupid light bulbs.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!