The Java Collections Framework (JCF) is a standardized architecture in the java.util
package that provides interfaces, classes, and algorithms to store, manipulate, and retrieve groups of objects in a consistent, efficient, and reusable manner.
It eliminates the need to write custom data structures from scratch, by offering a rich set of ready-made data structures (e.g., ArrayList
, HashSet
, HashMap
) and algorithms (e.g., sorting, searching, shuffling using the Collections
class).
History |
---|
Version | Major Updates & Features |
Java 1.2 | Initial introduction of Collections Framework Includes core interfaces and classes in java.util like List, Set, Map, Queue, etc. |
Java 1.5 | Generics for type safety Enhanced for-each loop (for (Type t : collection)) |
Java 1.6 | Performance improvements and minor concurrency enhancements Introduced ConcurrentSkipListMap, ConcurrentSkipListSet |
Java 1.7 | ➕ Diamond operator (<>) for type inference ➕ Try-with-resources (for safely managing Closeable resources) |
Java 1.8 | Lambda expressions and Streams API Functional-style operations: filter(), map(), collect() New collection methods: forEach(), removeIf() |
Java 9 | Factory methods for immutable collections: List.of(...), Set.of(...), Map.of(...) Internal improvements to Streams |
Java 10–13 | Minor enhancements to collection factories and Collectors e.g., Collectors.toUnmodifiableList() |
Java 14 | Pattern Matching (preview) — not direct, but aids functional-style control flows |
Java 15–16 | Performance tuning and internal Collections API cleanup |
Java 17 | LTS release: Stability, sealed types, and API enhancements Improved internal performance of collection types |
Java 18 | Stream.toList(): Convenient immutable terminal operation instead of collect(Collectors.toList()) |
Java 19–20 | Project Loom (virtual threads) — enhances concurrency libraries including concurrent collections |
Java 21 | Sequenced Collections API: Introduces SequencedCollection, SequencedSet, SequencedMap → Uniform access to getFirst(), getLast() across List, Deque, LinkedHashMap, etc. Also includes Record patterns, Sealed classes, etc. |
Features
-
Unified Architecture: Common interfaces like
List
,Set
,Map
, etc. -
Rich Set of Data Structures: Ready-to-use implementations such as
ArrayList
,HashMap
, etc. -
Type Safety with Generics
-
Algorithms Support: Sorting, searching using
Collections
class. -
Thread-Safe Variants: Synchronized and concurrent classes (
Vector
,ConcurrentHashMap
). -
Utility Classes:
Collections
,Arrays
,Objects
-
Integration with Functional Programming (Lambdas & Streams)
-
Concurrency Support via
java.util.concurrent
collections
Hierarchy
java.util.Collection (Interface) : Root interface representing a group of objects (aka "elements")
├── List (Interface) – Ordered, allows duplicates│ ├── ArrayList – Dynamic array, fast random access
│ ├── LinkedList – Doubly linked list, fast insertion/deletion
│ ├── Vector – Legacy synchronized list
│ │ └── Stack – Legacy LIFO stack (extends Vector)
├── Set (Interface) – Unordered, no duplicates
│ ├── HashSet – Hash table backed, fast lookup
│ │ └── LinkedHashSet – Preserves insertion order
│ └── SortedSet (Interface) – Sorted in natural/custom order
│ └── NavigableSet (Interface) – Extends SortedSet, navigation methods
│ └── TreeSet – Sorted set implemented via Red-Black tree
├── Queue (Interface) – FIFO or priority-based ordering
│ ├── LinkedList – Implements both List and Queue
│ ├── PriorityQueue – Elements ordered by natural/custom comparator
│ └── ArrayDeque – Resizable-array implementation of Deque
└── Deque (Interface) – Double-ended queue
├── ArrayDeque – Efficient stack/queue
└── LinkedList – Implements Deque, List, Queue
Utility Classes (Non-instantiable helper classes) : Provide helper methods for collection and array operations
├── Collections – Algorithms (sort, reverse, shuffle), sync wrappers├── Arrays – Utility methods for arrays (sort, binarySearch, etc.)
├── Objects – Null-safe utilities (equals, hash, etc.)
├── EnumSet – Efficient Set for enum values
├── EnumMap – Efficient Map for enum keys
├── WeakHashMap – Keys eligible for GC if no external ref
├── IdentityHashMap – Uses reference equality (==) instead of equals()
├── Properties – Used for config as key-value pairs (extends Hashtable)
Legacy Classes and Interfaces : Older APIs, mostly replaced by newer JCF constructs
├── Dictionary (Abstract class) – Superclass of Hashtable, obsolete├── Enumeration (Interface) – Predecessor to Iterator
└── Stack – Legacy LIFO stack (use Deque instead)
Sorting & Comparison Interfaces : Define rules for object comparison and ordering
├── Comparable (Interface) – Natural ordering (`compareTo`)├── Comparator (Interface) – Custom ordering (`compare`)
Iterator Interfaces : Provide cursor-style traversal for collections (forward, backward, or parallel)├── Iterator (Interface) – Universal forward-only iterator (all collections)
• Methods: hasNext(), next(), remove()
├── ListIterator (Interface) – Bi-directional iterator for List
• Methods: hasNext(), hasPrevious(), add(), set(), remove()
├── Enumeration (Interface) – Legacy read-only iterator (Vector, Hashtable)
• Methods: hasMoreElements(), nextElement()
├── Spliterator (Interface) – For parallel/bulk traversal (Streams, ForkJoin)
• Methods: trySplit(), forEachRemaining(), estimateSize()
java.util.Map (Interface) : Stores key-value pairs (not part of Collection hierarchy)
├── HashMap – General-purpose, allows one null key, many null values └── LinkedHashMap – Maintains insertion order
├── TreeMap – Sorted by natural/comparator order (implements SortedMap, NavigableMap)
├── Hashtable – Legacy synchronized map, does not allow null keys/values
├── ConcurrentMap (Interface) – For thread-safe maps
└── ConcurrentHashMap – High-performance concurrent map
java.util.concurrent (Concurrent Collections) : Thread-safe collections for concurrent use
├── CopyOnWriteArrayList – Thread-safe variant of ArrayList├── CopyOnWriteArraySet – Thread-safe Set
├── ConcurrentLinkedQueue – Lock-free thread-safe queue
├── ConcurrentHashMap – Thread-safe Map
Examples
List Interface : Ordered collection, allows duplicates. Ideal for indexed access and preserving insertion order.
🔹 ArrayList – Dynamic Array (Shopping Cart)
List<String> cart = new ArrayList<>();
cart.add("Laptop");
cart.add("Headphones");
cart.add("Mouse");
System.out.println("Items in cart: " + cart);
// Output: Items in cart: [Laptop, Headphones, Mouse]
📌 Use Case: Maintain order, fast random access, allow duplicates.
🔹 LinkedList – Doubly Linked List (Music Playlist)
List<String> playlist = new LinkedList<>();
playlist.add("Song A");
playlist.addFirst("Intro");
playlist.addLast("Outro");
System.out.println("Playlist: " + playlist);
// Output: Playlist: [Intro, Song A, Outro]
📌 Use Case: Frequent insertions/deletions at head or tail.
🔹 Vector – Legacy Thread-safe List (Audit Logs)
Vector<String> logs = new Vector<>();
logs.add("User1 logged in");
logs.add("User2 logged out");
System.out.println("Logs: " + logs);
// Output: Logs: [User1 logged in, User2 logged out]
📌 Use Case: Synchronized alternative to ArrayList (legacy).
🔹 Stack – LIFO Stack (Browser Back Button)
Stack<String> history = new Stack<>();
history.push("Home");
history.push("Profile");
System.out.println("Back to: " + history.pop());
// Output: Back to: Profile
📌 Use Case: Last-In-First-Out behavior like undo/history.
Set Interface : Unordered, unique elements. Prevents duplicates.
🔹 HashSet – Unique Elements (Registered Emails)
Set<String> emails = new HashSet<>();
emails.add("a@example.com");
emails.add("b@example.com");
emails.add("a@example.com"); // Ignored
System.out.println("Emails: " + emails);
// Output: Emails: [a@example.com, b@example.com] (order not guaranteed)
📌 Use Case: Unique entries, fast lookup.
🔹 LinkedHashSet – Ordered Unique Elements (Visitor Order)
Set<String> visitors = new LinkedHashSet<>();
visitors.add("Alice");
visitors.add("Bob");
System.out.println("Visit Order: " + visitors);
// Output: Visit Order: [Alice, Bob]
📌 Use Case: Maintain insertion order of unique items.
🔹 TreeSet – Sorted Unique Elements (Leaderboard Scores)
Set<Integer> scores = new TreeSet<>();
scores.add(90);
scores.add(85);
scores.add(95);
System.out.println("Sorted Scores: " + scores);
// Output: Sorted Scores: [85, 90, 95]
📌 Use Case: Sorted unique elements (natural or custom order).
Queue Interface : FIFO processing. Ideal for task scheduling.
🔹 LinkedList (as Queue) – (Customer Queue)
Queue<String> queue = new LinkedList<>();
queue.offer("Customer1");
queue.offer("Customer2");
System.out.println("Serving: " + queue.poll());
// Output: Serving: Customer1
📌 Use Case: Add at rear, remove from front.
🔹 PriorityQueue – Min-Heap Queue (Task Scheduling)
Queue<Integer> tasks = new PriorityQueue<>();
tasks.offer(3); // Low priority
tasks.offer(1); // High priority
tasks.offer(2);
System.out.println("Next task: " + tasks.poll());
// Output: Next task: 1
📌 Use Case: Automatically prioritize tasks.
Deque Interface : Double-ended operations. Stack + Queue.
🔹 ArrayDeque – Efficient Deque (Undo System)
Deque<String> actions = new ArrayDeque<>();
actions.push("Typed A");
actions.push("Typed B");
System.out.println("Undo: " + actions.pop());
// Output: Undo: Typed B
📌 Use Case: Use as stack or queue with better performance.
🔹 LinkedList (as Deque) – (Page History Navigation)
Deque<String> history = new LinkedList<>();
history.add("Page1");
history.add("Page2");
System.out.println("Back: " + history.removeLast());
// Output: Back: Page2
📌 Use Case: Flexible insert/delete from both ends.
Utility Classes : Provide static methods to easily create, modify, and work with collections, helping with tasks like sorting, searching, copying, and creating unmodifiable or thread-safe collections.
🔹 Collections – Helper Methods (List Operations)
List<Integer> numbers = Arrays.asList(5, 2, 8);
Collections.sort(numbers);
System.out.println("Sorted: " + numbers);
// Output: Sorted: [2, 5, 8]
📌 Use Case: Sort, reverse, synchronize, shuffle collections.
🔹 Arrays – Array Utilities (Sorting Arrays)
int[] arr = {4, 1, 3};
Arrays.sort(arr);
System.out.println("Sorted Array: " + Arrays.toString(arr));
// Output: Sorted Array: [1, 3, 4]
📌 Use Case: Work with primitive and object arrays efficiently.
🔹 Objects – Null-safe Checks (Equality Check)
String a = null;
String b = "Java";
System.out.println("Equal? " + Objects.equals(a, b));
// Output: Equal? false
📌 Use Case: Null-safe comparison, hash code generation.
..more Utility Classes
Utility Class
Description with Example
Collections
Static utility methods for manipulating collections – sort, shuffle, reverse, binary search, min/max, synchronized/unmodifiable wrappers, and more.
Example: Collections.sort(list), Collections.shuffle(list), Collections.reverse(list), Collections.synchronizedList(new ArrayList<>())
Arrays
Utilities for performing operations on arrays – sort, binary search, fill, copy, equals, and conversion to lists.
Example: Arrays.sort(arr), Arrays.binarySearch(arr, 10), Arrays.asList("A", "B")
Stream API
Enables functional-style processing of collections with lazy evaluation and support for parallelism. Common operations include map(), filter(), reduce(), collect(), etc.
Example: list.stream().filter(s -> s.startsWith("A")).collect(Collectors.toList())
Objects
Utility methods for null-safety and value comparison – used frequently in collection utilities.
Example: Objects.requireNonNull(obj), Objects.equals(a, b)
Optional
A container object for handling nullable values in a functional way, avoiding NullPointerException.
Example: Optional.ofNullable(name).ifPresent(System.out::println)
Comparator
Provides static methods like comparing(), thenComparing(), and reverseOrder() for building complex sorting logic.
Example: list.sort(Comparator.comparing(Person::getName).thenComparing(Person::getAge))
Map.Entry.
comparingByKey
/Value
Static helper methods for sorting map entries by keys or values using streams.
Example: map.entrySet().stream().sorted(Map.Entry.comparingByValue()).forEach(System.out::println)
Collectors
Provides terminal operations for collecting stream results into List, Map, sets, etc., or for grouping, partitioning, joining, and reducing.
Example: list.stream().collect(Collectors.groupingBy(s -> s.substring(0, 1)))
EnumSet / EnumMap
Specialized high-performance Set and Map implementations for use with enum types.
Example: EnumSet.of(Day.MONDAY, Day.FRIDAY)
Spliterator
Advanced iterator that supports parallelism, splitting, and bulk traversal of elements – used internally by streams.
Example: Spliterator<String> sp = list.spliterator(); sp.forEachRemaining(System.out::println)
List.of / Set.of / Map.of
(Java 9+)
Factory methods for creating immutable collections easily and concisely.
Example: List.of("A", "B"), Map.of("Alice", 90, "Bob", 80)
copyOf
(Java 10+)
Static methods to create unmodifiable copies of existing collections.
Example: List.copyOf(modifiableList)
Arrays.parallelSort()
Sorts large arrays using the fork/join framework for parallelism and better performance.
Example: Arrays.parallelSort(bigArray)
Pattern Matching
(Java 16–21)
Enhances instanceof and switch with type inference and extraction for concise conditional logic.
Example: if (obj instanceof String s) { System.out.println(s.toUpperCase()); }
SequencedCollection / Map / Set
(Java 21)
New interfaces providing consistent access to the first and last elements across ordered collections.
Example: map.firstEntry(), map.lastEntry()
Sealed Interfaces / Classes
(Java 17+)
Used to restrict which classes/interfaces can implement or extend a given type, useful for designing secure APIs.
Example: sealed interface MyList permits MyArrayList, MyLinkedList{}
Specialised Collections : Efficient implementations for special data structures.
🔹 EnumSet – Set for Enums (User Roles)
enum Role { ADMIN, USER, GUEST }
EnumSet<Role> roles = EnumSet.of(Role.ADMIN, Role.USER);
System.out.println("Roles: " + roles);
// Output: Roles: [ADMIN, USER]
📌 Use Case: Fast, memory-efficient set of enum values.
🔹 EnumMap – Map for Enums (Daily Schedule)
enum Day { MON, TUE }
EnumMap<Day, String> schedule = new EnumMap<>(Day.class);
schedule.put(Day.MON, "Gym");
System.out.println("Monday: " + schedule.get(Day.MON));
// Output: Monday: Gym
📌 Use Case: Fast and efficient map for enum keys.
🔹 WeakHashMap – GC-aware Map (Temporary Caching)
WeakHashMap<Object, String> map = new WeakHashMap<>();
Object key = new Object();
map.put(key, "TempData");
key = null; // Eligible for GC
System.gc();
📌 Use Case: Auto-remove entries when key is no longer referenced.
🔹 IdentityHashMap – Ref-based Map (Object Identity Tracking)
IdentityHashMap<String, String> idMap = new IdentityHashMap<>();
idMap.put(new String("A"), "First");
idMap.put(new String("A"), "Second");
System.out.println("Size: " + idMap.size());
// Output: Size: 2
📌 Use Case: Key comparison using ==
instead of .equals()
.
🔹 Properties – Config Management (App Settings)
Properties config = new Properties();
config.setProperty("env", "prod");
System.out.println("Environment: " + config.getProperty("env"));
// Output: Environment: prod
📌 Use Case: Store/load configuration from .properties
files.
Comparison Interfaces : Define custom and natural sorting logic.
🔹 Comparable – Natural Sorting (Student Age Sorting)
class Student implements Comparable<Student> {
String name;
int age;
Student(String n, int a) { name = n; age = a; }
public int compareTo(Student s) { return this.age - s.age; }
public String toString() { return name + " (" + age + ")"; }
}
List<Student> list = new ArrayList<>();
list.add(new Student("John", 25));
list.add(new Student("Alice", 20));
Collections.sort(list);
System.out.println(list);
// Output: [Alice (20), John (25)]
📌 Use Case: Natural ordering of objects (e.g., by age).
🔹 Comparator – Custom Sorting (Sort by Name)
Comparator<Student> byName = (s1, s2) -> s1.name.compareTo(s2.name);
Collections.sort(list, byName);
System.out.println(list);
// Output: [Alice (20), John (25)]
📌 Use Case: Define multiple or custom sorting logic.
Iterator Interfaces : Allow cursor-based traversal (forward, bidirectional, or parallel) over collection elements, with optional modification.
🔹 Iterator – Forward-only Traversal (Remove During Iteration)
List<String> items = new ArrayList<>(Arrays.asList("Keep", "Remove", "Keep"));
Iterator<String> iterator = items.iterator();
while (iterator.hasNext()) {
if (iterator.next().equals("Remove")) {
iterator.remove(); // Safely removes "Remove"
}
}
System.out.println(items);
// Output: [Keep, Keep]
📌 Use Case: Traverse any collection one-way and safely remove elements during iteration.
🔹 ListIterator – Bi-directional Traversal (Modify During Iteration)
List<String> colors = new ArrayList<>(Arrays.asList("Red", "Green", "Blue"));
ListIterator<String> listIterator = colors.listIterator();
while (listIterator.hasNext()) {
String color = listIterator.next();
if (color.equals("Green")) {
listIterator.set("Lime"); // Replace "Green" with "Lime"
}
}
System.out.println(colors);
// Output: [Red, Lime, Blue]
// Backward traversal
while (listIterator.hasPrevious()) {
System.out.println("Back: " + listIterator.previous());
}
// Output:
// Back: Blue
// Back: Lime
// Back: Red
📌 Use Case: Traverse List
forward/backward and modify elements with set()
, add()
, remove()
.
🔹 Enumeration – Legacy Read-Only Traversal (Vector Example)
Vector<String> vec = new Vector<>();
vec.add("One");
vec.add("Two");
Enumeration<String> enumeration = vec.elements();
while (enumeration.hasMoreElements()) {
System.out.println(enumeration.nextElement());
}
// Output:
// One
// Two
📌 Use Case: Forward-only read operations on legacy collections like Vector
, Hashtable
.
🔹 Spliterator – Bulk + Parallel Traversal (Streams Compatible)
List<String> fruits = Arrays.asList("Apple", "Banana", "Mango");
Spliterator<String> spliterator = fruits.spliterator();
spliterator.forEachRemaining(System.out::println);
// Output:
// Apple
// Banana
// Mango
// Splitting and processing in parallel (conceptual)
Spliterator<String> s1 = fruits.spliterator();
Spliterator<String> s2 = s1.trySplit();
s1.forEachRemaining(f -> System.out.println("Part1: " + f));
s2.forEachRemaining(f -> System.out.println("Part2: " + f));
//Possible Output:
//Part2: Apple
//Part1: Banana
//Part1: Mango
📌 Use Case: High-performance or parallel iteration in large or stream-based datasets using trySplit()
.
Map Interface : Key-value pair storage. Fast retrieval via keys.
🔹 HashMap – General Map (User Directory)
Map<Integer, String> users = new HashMap<>();
users.put(101, "Alice");
users.put(102, "Bob");
System.out.println("User 101: " + users.get(101));
// Output: User 101: Alice
📌 Use Case: Fast, non-sorted key access.
🔹 LinkedHashMap – Ordered Map (Page Cache)
Map<String, String> pages = new LinkedHashMap<>();
pages.put("home", "HomePage");
pages.put("contact", "ContactPage");
System.out.println("Pages: " + pages);
// Output: Pages: {home=HomePage, contact=ContactPage}
📌 Use Case: Maintain insertion or access order (e.g. LRU).
🔹 TreeMap – Sorted Key Map (Employee Directory)
Map<Integer, String> emp = new TreeMap<>();
emp.put(3002, "Ravi");
emp.put(1001, "Anita");
System.out.println("Sorted Employees: " + emp);
// Output: Sorted Employees: {1001=Anita, 3002=Ravi}
📌 Use Case: Automatically sorted key-value pairs.
🔹 Hashtable – Legacy Thread-Safe Map (System Config)
Hashtable<String, String> config = new Hashtable<>();
config.put("theme", "dark");
System.out.println("Theme: " + config.get("theme"));
// Output: Theme: dark
📌 Use Case: Synchronized map (legacy).
🔹 ConcurrentHashMap – Concurrent Map (Live Counters)
Map<String, Integer> counter = new ConcurrentHashMap<>();
counter.put("visits", 10);
System.out.println("Visits: " + counter.get("visits"));
// Output: Visits: 10
📌 Use Case: High-performance thread-safe map.
Concurrent Collections : Thread-safe alternatives for multi-threaded environments.
🔹 CopyOnWriteArrayList – Thread-safe List (Event Listeners)
CopyOnWriteArrayList<String> listeners = new CopyOnWriteArrayList<>();
listeners.add("Listener1");
listeners.add("Listener2");
System.out.println("Listeners: " + listeners);
// Output: Listeners: [Listener1, Listener2]
📌 Use Case: Safe iteration during concurrent modifications.
🔹 CopyOnWriteArraySet – Thread-safe Set (Subscribed Users)
CopyOnWriteArraySet<String> subscribers = new CopyOnWriteArraySet<>();
subscribers.add("user1@example.com");
subscribers.add("user2@example.com");
System.out.println("Subscribers: " + subscribers);
// Output: Subscribers: [user1@example.com, user2@example.com]
📌 Use Case: No duplicates + thread-safe for read-heavy operations.
🔹 ConcurrentLinkedQueue – Non-blocking Queue (Async Task Queue)
Queue<String> queue = new ConcurrentLinkedQueue<>();
queue.offer("Task1");
queue.offer("Task2");
System.out.println("Processing: " + queue.poll());
// Output: Processing: Task1
📌 Use Case: Lock-free FIFO queue for concurrent environments.
Decision Tree
Start
│
│── Do you need to store key-value pairs (mapping)?
│ │── Yes → Use a Map
│ │ │── Need ordering by keys?
│ │ │ │── Natural/comparator order → TreeMap
│ │ │ └── Insertion order → LinkedHashMap
│ │ │── Need thread safety?
│ │ │ │── High concurrency → ConcurrentHashMap
│ │ │ └── Legacy synchronized → Hashtable
│ │ │── Need enum keys? → EnumMap
│ │ └── Just a general-purpose map → HashMap
│ └── No → Use a Collection
│
│── Do you allow duplicates?
│ │── Yes → Use a List or Queue
│ │ │── Need ordering?
│ │ │ │── Yes → Use a List
│ │ │ │ │── Random access → ArrayList
│ │ │ │ └── Frequent insert/remove → LinkedList
│ │ │ └── No → Use a Queue
│ │ │ │── Priority-based order → PriorityQueue
│ │ │ │── FIFO with fast inserts/removals → LinkedList
│ │ │ └── Fast deque stack/queue → ArrayDeque
│ └── No → Use a Set
│ │── Need sorted order?
│ │ │── Yes → TreeSet
│ │ └── No → Continue
│ │── Need insertion order preserved? → LinkedHashSet
│ └── General-purpose set → HashSet
│
│── Do you need thread-safe collection?
│ │── Yes
│ │ │── For List → CopyOnWriteArrayList
│ │ │── For Set → CopyOnWriteArraySet
│ │ │── For Queue → ConcurrentLinkedQueue
│ │ │── For Map → ConcurrentHashMap
│ │ └── Legacy (not preferred) → Collections.synchronizedXXX()
│ └── No → Use non-thread-safe collections
│
└── Do you need stack or double-ended queue?
│── Yes
│ │── Use ArrayDeque (preferred over Stack)
│ └── Use LinkedList if list+queue needed
└── No → Use based on above decisions