A simple, book-style explanation of Java's Collections Framework
A program frequently needs to store a group of objects: students, products, accounts, names, orders, or numbers. Java could provide a different class for every possible requirement, but that would make programs harder to learn and maintain. The Collections Framework provides a common design so that different collection types can be handled in a consistent way.
The framework was designed around several important goals:
The main collection hierarchy starts with Iterable, then Collection, which is extended by interfaces such as List, Set, and Queue. Map is part of the Collections Framework but is a separate hierarchy because it stores key-value pairs rather than individual collection elements.
| Interface | Simple description |
|---|---|
| Collection<E> | Works with groups of objects and forms the foundation of the collection hierarchy. |
| List<E> | Represents a sequence of elements. It provides index-based access and normally allows duplicates. |
| Set<E> | Represents a group of unique elements. Duplicate elements are not allowed. |
| Queue<E> | Represents a collection designed for elements that are waiting to be processed. |
| Deque<E> | Extends Queue and supports operations at both ends of the queue. |
| SortedSet<E> | Extends Set and maintains elements in sorted order. |
| NavigableSet<E> | Extends SortedSet and adds navigation and closest-match search operations. |
The framework also uses related interfaces:
The Collection<E> interface is the foundation of the main collection hierarchy. The type parameter E represents the type of element stored in the collection. Because Collection extends Iterable, its implementations can be processed with the enhanced for loop.
| Method | Purpose |
|---|---|
| add(E) | Adds an element. |
| addAll(Collection) | Adds all elements from another collection. |
| remove(Object) | Removes an element. |
| removeAll(Collection) | Removes elements that occur in another collection. |
| retainAll(Collection) | Keeps only elements that occur in another collection. |
| removeIf(Predicate) | Removes elements that satisfy a condition. |
| clear() | Removes all elements. |
| contains(Object) | Checks whether an element exists. |
| containsAll(Collection) | Checks whether all elements of another collection are present. |
| isEmpty() | Checks whether the collection contains no elements. |
| size() | Returns the number of elements. |
| iterator() | Returns an Iterator. |
| toArray() | Converts collection contents into an array. |
| stream() | Returns a sequential Stream from the collection. |
| parallelStream() | Returns a stream that can support parallel processing when possible. |
Some collection operations are optional because not every collection supports modification. A collection that permits modification is called modifiable. A collection that does not allow its contents to change is called unmodifiable.
A List represents an ordered sequence of elements. Elements can normally be accessed by an integer index, beginning at zero, and duplicate elements are allowed.
Output:
| Method | Purpose |
|---|---|
| add(int, E) | Inserts an element at a specific index. |
| addAll(int, Collection) | Inserts another collection at a specific index. |
| get(int) | Returns the element at an index. |
| set(int, E) | Replaces the element at an index. |
| indexOf(Object) | Returns the first matching index, or -1. |
| lastIndexOf(Object) | Returns the last matching index, or -1. |
| subList(int, int) | Provides a view of a portion of the list. |
| sort(Comparator) | Sorts the list according to the supplied comparison rule. |
| listIterator() | Returns a ListIterator. |
A Set represents a collection in which duplicate elements are not allowed.
Only one occurrence of `"Java"` can be stored.
SortedSet extends Set and adds the idea of sorted elements. NavigableSet extends SortedSet and provides operations for navigating around values, including closest-match searches.
The common concrete implementation is TreeSet.
A Queue represents a collection designed for holding elements before they are processed. Queue operations commonly distinguish between examining, retrieving, and removing the head element.
Output:
| Purpose | Common methods |
|---|---|
| Insert | add(), offer() |
| Examine head | element(), peek() |
| Remove head | remove(), poll() |
Deque means double-ended queue. It extends Queue and supports adding, examining, and removing elements from either end.
Conceptually:
| Class | Main idea |
|---|---|
| ArrayList | Resizable-array implementation of List. Efficient for indexed access. |
| LinkedList | Linked-node implementation of List and Deque. Supports list and double-ended queue operations. |
| HashSet | Set implementation based on hashing. Does not guarantee element order. |
| LinkedHashSet | HashSet variant that maintains insertion-order iteration. |
| TreeSet | Sorted Set implementation based on a tree. |
| PriorityQueue | Queue implementation that retrieves its head according to its ordering rules. |
| ArrayDeque | Resizable-array implementation of Deque. |
| EnumSet | Specialized Set designed for enum elements. |
ArrayList<E> is a resizable-array implementation of List. It is particularly useful when your program frequently accesses elements by index.
Output:
LinkedList<E> implements List, Deque, and Queue. It provides linked-list behavior and therefore supports operations at both ends.
Useful methods include:
HashSet<E> uses hashing to store a Set of unique elements. It does not guarantee the order of its elements.
The duplicate `"Beta"` is not added.
TreeSet is a Set implementation that maintains elements according to sorted ordering.
Output:
PriorityQueue is a Queue implementation. The element retrieved from its head is determined by the queue's ordering rules.
With natural ordering for integers, the output is:
ArrayDeque provides a resizable-array implementation of Deque. It can be used as a queue or as a stack.
Output:
This demonstrates stack behavior: the last element pushed is the first one removed.
EnumSet is a specialized Set for enum values. It is designed specifically for use with enum types.
An Iterator provides a standardized way to access elements in a collection one at a time. This means code that traverses one collection can often be adapted easily to another collection.
| Method | Purpose |
|---|---|
| hasNext() | Returns true when another element is available. |
| next() | Returns the next element. |
| remove() | Removes the current element when supported by the iterator. |
| forEachRemaining() | Processes remaining elements using the supplied action. |
ListIterator is designed specifically for Lists. Unlike a basic Iterator, it supports traversal in both directions and provides additional list operations.
It provides operations such as:
Java 8 introduced Spliterator. It is an iterator-like mechanism designed to support traversal that can be split into parts, which is useful for parallel processing.
RandomAccess is a marker interface. It does not declare methods. When a List implements it, the List indicates that indexed access can be performed efficiently.
ArrayList is an example of a List designed for efficient random access.
A Map<K,V> stores key-value pairs. The key identifies the value, and keys are unique within a map.
Output:
The framework also defines SortedMap, NavigableMap, and Map.Entry.
| Method | Purpose |
|---|---|
| put(K,V) | Adds or replaces a key-value mapping. |
| get(Object) | Returns the value associated with a key. |
| remove(Object) | Removes a mapping by key. |
| containsKey(Object) | Checks whether a key exists. |
| containsValue(Object) | Checks whether a value exists. |
| size() | Returns the number of mappings. |
| isEmpty() | Checks whether the map contains no mappings. |
| clear() | Removes all mappings. |
| keySet() | Returns a Set view of the keys. |
| values() | Returns a collection view of the values. |
| entrySet() | Returns a Set view of the key-value entries. |
| putIfAbsent() | Adds a mapping only when the key is not already mapped. |
| getOrDefault() | Returns a value or a specified default when the key is absent. |
Each key-value pair in a Map can be represented by a Map.Entry<K,V>. This is useful when processing both the key and its value together.
HashMap<K,V> uses a hash table to store mappings. It is designed for efficient get() and put() operations. It does not guarantee the order of its elements.
Output:
TreeMap<K,V> uses a tree and maintains its keys according to sorted ordering.
The keys are maintained in sorted order:
| Class | Simple description |
|---|---|
| HashMap | Map implementation based on hashing. |
| TreeMap | Map implementation based on a tree and sorted keys. |
| LinkedHashMap | HashMap variant that supports insertion-order iteration. |
| EnumMap | Map designed for enum keys. |
| WeakHashMap | Map using weak keys, allowing entries to become eligible for garbage collection when their keys are otherwise unused. |
| IdentityHashMap | Map that uses reference identity when comparing keys. |
A Comparator defines how two objects should be compared. This is especially useful when a collection needs an ordering different from an object's natural ordering.
The comparator causes the TreeSet to use the comparison rule supplied to it.
The Collections class provides static algorithms that operate on collections. This gives the framework a standard way to manipulate collections instead of requiring every collection class to implement its own sorting and searching algorithms.
| Method | Purpose |
|---|---|
| sort() | Sorts a List. |
| binarySearch() | Searches a sorted List. |
| reverse() | Reverses the order of a List. |
| shuffle() | Randomly rearranges a List. |
| min() | Finds the minimum element according to ordering. |
| max() | Finds the maximum element according to ordering. |
| rotate() | Rotates elements in a List. |
| frequency() | Counts occurrences of an object. |
| fill() | Replaces all elements in a List with a specified value. |
| copy() | Copies elements from one List to another. |
| replaceAll() | Replaces all occurrences of one value with another. |
Output:
The Collections class also provides methods for creating unmodifiable views of collections. These views allow a collection to be exposed without allowing callers to modify it through that view.
Java provides the Arrays utility class for common array operations. The framework also provides ways to move between arrays and collections.
| Method | Purpose |
|---|---|
| sort() | Sorts an array. |
| binarySearch() | Searches a sorted array. |
| fill() | Fills an array or part of an array with a value. |
| copyOf() | Creates a copy of an array. |
| copyOfRange() | Copies a specified range of an array. |
| equals() | Compares array contents. |
| toString() | Creates a readable representation of an array. |
| deepToString() | Creates a readable representation for nested arrays. |
| mismatch() | Finds the first index at which two arrays differ. |
Output:
Collections use generics to specify the type of elements they store.
In Map<K,V>, K represents the key type and V represents the value type.
Collections store object references rather than primitive values. Java's autoboxing feature makes it convenient to work with primitive values.
The primitive int values are automatically boxed into Integer objects when they are added.
Use List. A common implementation is ArrayList.
Use Set. Choose HashSet when sorted order is not required and TreeSet when sorted order is needed.
Use Queue or Deque. Examples include PriorityQueue and ArrayDeque.
Use Map. Choose HashMap or TreeMap according to ordering requirements.
| Collection | Map |
|---|---|
| Stores individual elements. | Stores key-value pairs. |
| Examples: List, Set, Queue. | Examples: HashMap, TreeMap. |
| Elements are accessed as collection elements. | Values are normally accessed using keys. |
| Can be traversed through Collection/Iterator mechanisms. | Provides views such as keySet(), values(), and entrySet(). |
Before the Collections Framework was added, Java provided older classes for storing groups of objects. Some of these classes were later integrated with the collection interfaces.
| Legacy type | Modern perspective |
|---|---|
| Vector | Older dynamic-array class. Modern List implementations are usually preferred for new code when Vector-specific behavior is not needed. |
| Stack | Older stack class. Deque implementations such as ArrayDeque are generally preferred for stack behavior in new code. |
| Hashtable | Older synchronized map class. Modern Map implementations are generally preferred when its legacy behavior is not required. |
| Dictionary | Legacy abstract class for key-value mappings. |
| Properties | Legacy utility class for property data. |
| Enumeration | Older traversal interface that has been superseded by Iterator for general collection traversal. |
Do not try to memorize every collection class first. Start with the data requirement.
Once you know the required behavior, choose an implementation based on ordering, access patterns, and other requirements.