Arrays are good and fast, but they are static (once they are created they can’t grow). In this lesson we’re going to review three hierarchically related types from the Java Collections API that provide dynamic data structures:
Type | extends |
implements |
Description |
---|---|---|---|
interface Collection |
Iterable |
– | General dynamic collection of elements that is iterable |
interface List |
Collection |
– | Dynamic collection providing also positional access |
class ArrayList |
ArrayList |
List
|
Implementation of List providing fast positional access |
The Collection Interface
The Collection
interface is used when maximum generality is desired. The following table lists the main methods of this interface:
Basic Operations | |
---|---|
int size() boolean isEmpty() boolean contains(Object element) boolean add(E element) boolean remove(Object element) |
The method remove(e) returns true if the collection contained e |
Bulk Operations | |
boolean containsAll(Collection<?> c) boolean addAll(Collection<?> c) boolean removeAll(Collection<?> c) void clear() |
Bulk operations equivalent to the basic operations, e.g.: removeAll removes all elements of this that are in c |
Iterable Operations |
|
Iterator<E> iterator() |
Implementing this interface allows an object to be the target of a for-each loop |
Array Operations | |
Object[] toArray() <T> T[] toArray(T[] a) |
Example:String[] sa = 
c.toArray(new String[0]); |
You can traverse any given collection c
in two ways:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// a) Traversing a Collection with a for-each loop for (Object o : c) { // do something with the collection element o … } // b) Traversing a Collection with an Iterator for (Iterator<Object> it = c.iterator(); it.hasNext(); ) { Object o = it.next(); // do something with the collection element o … } |
Use Iterator
instead of the for-each loop when you need to:
- Iterate over multiple collections in parallel
- Remove the current element (
it.remove()
it’s the only safe way to do it during iteration)
The List Interface
The List
interface inherits all the operations from the Collection
interface and mainly adds to them positional access and search operations:
Positional Access1 | |
---|---|
E get(int index) E set(int index, E element) void add(int index, E element) E remove(int index) |
|
Search Operations | |
int indexOf(Object o) int lastIndexOf(Object o) |
Returns the index of the first (or last) occurrence of the specified element in this list, or -1 if the element is not found |
You can think of a List
as an ordered collection that allows duplicates. Two List
objects are equal if they contain the same (according to equals
method) elements and in the same order.
The ArrayList Class
The ArrayList
class is probably the most used implementation of the List
interface. It is internally backed up by an array and provides fast (constant-time) positional access.
Since it is a dynamic collection that grows automatically, you don’t have to worry about its size, except if you try to add elements at a specific index (in order to add an element at index i
the ArrayList must have at least i
elements or an exception will be thrown).
1 2 3 4 5 6 7 |
// ArrayList example ArrayList<Integer> al = new ArrayList<>(); al.add(new Integer(1)); al.add(0, new Integer(2)); al.remove(1); |
The Vector
class is the equivalent thread-safe collection that it’s used when synchronization is needed. Because of this synchronization overhead it’s slightly slower than ArrayList
.
You can create an ArrayList
or a Vector
object using the existing data in another Collection
object to initially populate it:
1 2 3 |
List<String> list = new ArrayList<String>(collection); |