Java Collections Framework

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

├── CopyOnWriteArrayListThread-safe variant of ArrayList
├── CopyOnWriteArraySetThread-safe Set ├── ConcurrentLinkedQueueLock-free thread-safe queue ├── ConcurrentHashMapThread-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 Interface: 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