We'll start with Part 1: Java Collections Framework Overview. This is foundational. If you don't understand why the framework exists and how it's organized, the internal implementations of ArrayList, HashMap, and ConcurrentHashMap won't make as much sense.
Part 1 β Java Collections Framework OverviewΒΆ
1. What is the Java Collections Framework (JCF)?ΒΆ
The Java Collections Framework (JCF) is a unified architecture for storing, manipulating, and accessing groups of objects.
It provides:
- Interfaces (contracts)
- Implementations (classes)
- Algorithms (utility methods)
Instead of writing your own data structures, you use well-tested implementations provided by the JDK.
Examples:
ArrayListLinkedListHashMapHashSetTreeMapPriorityQueue
2. Why was the Collections Framework introduced?ΒΆ
Before JDK 1.2, Java had legacy classes like:
VectorHashtableStackDictionaryEnumeration
Problems:
- No common interfaces
- Inconsistent APIs
- Limited reusability
- Mostly synchronized (poor performance in single-threaded code)
- Difficult to write generic algorithms
Example:
Vector vector = new Vector();
Hashtable table = new Hashtable();
These classes worked differently despite solving similar problems.
SolutionΒΆ
JDK 1.2 introduced the Collections Framework with common interfaces:
Collection
|
-------------------------
| | |
List Set Queue
Map (separate hierarchy)
Now algorithms can work with interfaces instead of concrete classes.
Example:
List<String> list = new ArrayList<>();
List<String> list2 = new LinkedList<>();
The code depends on the List interface, so implementations can be swapped with minimal changes.
3. Problems with ArraysΒΆ
Arrays are simple and efficient, but they have limitations.
Problem 1: Fixed SizeΒΆ
int[] arr = new int[5];
The size is fixed at creation.
Need more space?
You must create a new array and copy the elements.
Example:
int[] oldArray = {1,2,3};
int[] newArray = new int[6];
System.arraycopy(oldArray, 0, newArray, 0, oldArray.length);
This copy operation has a time complexity of O(n).
Problem 2: No Built-in OperationsΒΆ
Suppose you want to remove an element:
int[] arr = {10,20,30,40};
Removing 20 requires shifting all later elements:
Before
10 20 30 40
After
10 30 40 _
Time complexity:
O(n)
Problem 3: Arrays Store Fixed-Type ElementsΒΆ
String[] names = new String[10];
Only String objects can be stored.
Generics in collections provide better type safety and flexibility.
Problem 4: No Dynamic GrowthΒΆ
If the array becomes full:
Need larger array
β
Allocate new memory
β
Copy old elements
β
Discard old array
ArrayList automates this process.
Problem 5: Poor APIΒΆ
Arrays provide almost no useful methods.
Collections provide operations like:
add()
remove()
contains()
iterator()
stream()
sort()
4. Collection vs Collections vs StreamΒΆ
This is a very common interview question.
| Feature | Collection | Collections | Stream |
|---|---|---|---|
| Type | Interface | Utility class | Interface |
| Purpose | Store elements | Utility algorithms | Process data |
| Package | java.util | java.util | java.util.stream |
| Mutable | Yes (generally) | N/A | No |
| Stores data | Yes | No | No |
| Introduced | JDK 1.2 | JDK 1.2 | Java 8 |
CollectionΒΆ
Represents a group of objects.
Collection<String> c = new ArrayList<>();
CollectionsΒΆ
Utility class with static methods.
Collections.sort(list);
Collections.reverse(list);
Collections.shuffle(list);
StreamΒΆ
Used for processing data declaratively.
list.stream()
.filter(x -> x.startsWith("A"))
.sorted()
.forEach(System.out::println);
Streams do not modify the source collection unless you explicitly perform mutating operations elsewhere.
5. Iterable HierarchyΒΆ
Every collection that can be traversed implements Iterable.
Iterable
|
Collection
|
-------------------------
| | |
List Set Queue
The Iterable interface defines one essential method:
Iterator<T> iterator();
This is why you can use the enhanced for loop.
Example:
List<String> list = List.of("A", "B", "C");
for (String s : list) {
System.out.println(s);
}
The compiler translates it roughly into:
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
6. Complete Collections HierarchyΒΆ
Iterable
|
Collection
βββββββββββΌββββββββββ
β β β
List Set Queue
β β β
ArrayList HashSet PriorityQueue
LinkedList TreeSet ArrayDeque
Vector
Stack
Map (Separate Hierarchy)
Map
βββ HashMap
βββ LinkedHashMap
βββ TreeMap
βββ Hashtable
βββ ConcurrentHashMap
βββ WeakHashMap
βββ IdentityHashMap
βββ EnumMap
Why is Map separate?
A Collection stores individual elements, while a Map stores key-value pairs. Since a map does not conceptually represent a collection of single elements, it is not a subtype of Collection.
7. Core InterfacesΒΆ
| Interface | Stores | Duplicates | Ordering |
|---|---|---|---|
| List | Elements | Yes | Preserves insertion order |
| Set | Elements | No | Depends on implementation |
| Queue | Elements | Usually yes | FIFO or priority-based |
| Map | Key-value pairs | Duplicate keys not allowed | Depends on implementation |
8. Choosing the Right CollectionΒΆ
| Requirement | Collection |
|---|---|
| Fast random access | ArrayList |
| Frequent insertions/removals in the middle | LinkedList (though often ArrayList still performs better in practice due to cache locality) |
| Unique elements | HashSet |
| Sorted unique elements | TreeSet |
| Key-value lookup | HashMap |
| Sorted key-value pairs | TreeMap |
| Thread-safe concurrent map | ConcurrentHashMap |
| Priority processing | PriorityQueue |
| Fast deque operations | ArrayDeque |
Interview note: Don't choose LinkedList automatically for insertions/deletions. While its insertion is O(1) once you have the node, finding that node is typically O(n). For many real-world workloads, ArrayList is faster because of better CPU cache locality.
9. Time Complexity OverviewΒΆ
| Collection | Access | Search | Insert (end) | Insert (middle) | Delete |
|---|---|---|---|---|---|
| ArrayList | O(1) | O(n) | Amortized O(1) | O(n) | O(n) |
| LinkedList | O(n) | O(n) | O(1) | O(1)* | O(1)* |
| HashSet | N/A | O(1) average | O(1) average | N/A | O(1) average |
| HashMap | N/A | O(1) average | O(1) average | N/A | O(1) average |
| TreeSet | N/A | O(log n) | O(log n) | N/A | O(log n) |
| TreeMap | N/A | O(log n) | O(log n) | N/A | O(log n) |
*Assuming you already have a reference to the target node.
10. Interview QuestionsΒΆ
Q1. Why was the Collections Framework introduced?ΒΆ
Answer: To provide a unified architecture for data structures, common interfaces, reusable algorithms, improved code reuse, and consistent APIs.
Q2. Why doesn't Map extend Collection?ΒΆ
Answer: Because Collection represents a group of individual elements, while Map represents mappings from keys to values.
Q3. Difference between Collection and Collections?ΒΆ
Answer:
Collectionis an interface.Collectionsis a utility class containing static helper methods.
Q4. Difference between Collection and Iterable?ΒΆ
Answer:
Iterableprovides traversal viaiterator().CollectionextendsIterableand adds methods such asadd(),remove(),size(), andcontains().
Q5. Which interface supports the enhanced for loop?ΒΆ
Answer: Iterable.
Key TakeawaysΒΆ
- Understand why JCF was introduced, not just what it contains.
- Know the distinction between
Collection,Collections,Map, andStream. - Remember that
Mapis a separate hierarchy. - Learn the high-level hierarchy before diving into implementations.
- Be comfortable with the basic time complexities of common collections.
In the next part, we'll do a deep dive into ArrayList, covering its internal implementation, dynamic resizing, growth algorithm, modCount, fail-fast iterators, memory layout, and performance characteristics in detail.