Collections Framework overview

An array has a fixed size and very few tools. Real programs need lists that grow, sets that ignore duplicates, queues that serve customers in order, and maps that find a value by its key in an instant. Java's Collections Framework gives you all of these as ready-made, tested classes behind a small set of interfaces. This lesson is the map of the whole module: what each interface promises, which class to pick, and how they behave in memory.

Module 11 · Collections⏱ 22 minIntermediate8 practice problems
1 The story

The canteen that outgrew its array

Riya's canteen app started with String[] orders = new String[50];. On fest day there were 312 orders, the same customer was counted three times in “unique visitors”, the token queue was served out of order, and finding a dish's price meant looping over two parallel arrays.

Listorders, in sequence [chai, dosa, chai, vada …]grows, keeps repeats Setunique visitors {Riya, Kabir, Om}no duplicates Queuetoken counter T41 ← T42 ← T43first in, first out Mapdish → price chai → 15dosa → 60find by key, fast myphatshala.in
Riya

Sir, my array overflowed, my visitor count is wrong, and searching prices is slow. Do I need to write my own data structures?

Arjun Sir

No. Java already has them, tested by millions of programs. You have four different jobs here, so you need four different containers: a List for orders, a Set for unique visitors, a Queue for tokens and a Map for prices.

Riya

Four new things to learn?

Arjun Sir

Four interfaces, each a promise about behaviour, and a few classes that keep those promises in different ways. Learn the promises first; picking the class becomes easy.

2 Definition

What is the Collections Framework?

Formal definition (write this in exams)

The Java Collections Framework (in java.util, since Java 1.2) is a unified architecture for storing and manipulating groups of objects. It consists of interfaces (Collection, List, Set, Queue, Deque, Map and their sorted variants), implementations (such as ArrayList, LinkedList, HashSet, TreeSet, ArrayDeque, PriorityQueue, HashMap, TreeMap) and algorithms (static methods in Collections such as sort, max and frequency). Collections hold object references only, are generic, and (except for legacy classes) grow dynamically.

In simple words

A toolbox of ready-made containers for groups of objects. Each container type promises a behaviour (ordered? duplicates? first-in-first-out? lookup by key?), and you pick the one whose promise fits your job.

Words you'll meet in this lesson

CollectionThe root interface for a group of elements: add, remove, size, contains.
CollectionsA separate utility class with static helpers. Different from the interface!
OrderedElements keep a position or sequence (a List does).
SortedElements kept in natural or custom order (a TreeSet does).
Key–value pairA Map entry: you look up the value by its key.
Immutable collectionCan't be changed after creation: List.of(…), Map.of(…).

The family tree

Iterable
 └─ Collection
     ├─ List      → ArrayList, LinkedList            ordered, index, duplicates OK
     ├─ Set       → HashSet, LinkedHashSet           no duplicates
     │   └─ SortedSet → TreeSet                      sorted, no duplicates
     └─ Queue     → PriorityQueue                    process in order of priority
         └─ Deque → ArrayDeque, LinkedList           add/remove at both ends (queue or stack)

Map (NOT a Collection)  → HashMap, LinkedHashMap      key → value, keys unique
 └─ SortedMap → TreeMap                              keys sorted

Exam tip: Map does not extend Collection; it's a separate hierarchy. And Collection (interface, the root of List/Set/Queue) is not Collections (a utility class with static methods like sort). Both are classic MCQ traps.

3 Types and ways to use it

Four promises, and which class to pick

List

Ordered by position, duplicates allowed, get(i). Default: ArrayList.

orders, marks, history

Set

No duplicates. HashSet (fast), LinkedHashSet (keeps insertion order), TreeSet (sorted).

unique IDs, tags

Queue / Deque

Process in order. ArrayDeque (FIFO queue or LIFO stack), PriorityQueue (smallest first).

tokens, tasks, undo

Map

Key → value, unique keys. HashMap (fast), LinkedHashMap (insertion order), TreeMap (sorted keys).

prices, counts, caches

The same data in four containers

import java.util.*;

public class Main {
    public static void main(String[] args) {
        String[] visits = {"Riya", "Kabir", "Riya", "Om", "Riya"};

        List<String> log = new ArrayList<>(Arrays.asList(visits));    // keeps everything
        Set<String> unique = new HashSet<>(log);                     // drops repeats
        Set<String> sorted = new TreeSet<>(log);                     // drops repeats, sorts
        Queue<String> line = new ArrayDeque<>(log);                  // first in, first out
        Map<String, Integer> count = new TreeMap<>();
        for (String v : log) count.put(v, count.getOrDefault(v, 0) + 1);

        System.out.println("List : " + log);
        System.out.println("Set  : " + unique.size() + " unique");
        System.out.println("Tree : " + sorted);
        System.out.println("Queue: serve " + line.poll() + ", next " + line.peek());
        System.out.println("Map  : " + count);
    }
}
List : [Riya, Kabir, Riya, Om, Riya] Set : 3 unique Tree : [Kabir, Om, Riya] Queue: serve Riya, next Kabir Map : {Kabir=1, Om=1, Riya=3}

Choosing quickly

You need…UseKey operations (typical cost)
A sequence, read by positionArrayListget(i) O(1), add at end O(1) amortised
Many inserts/removes at the endsArrayDequeoffer/poll/push/pop O(1)
“Have I seen this before?”HashSetadd/contains O(1) average
Unique and sortedTreeSetadd/contains O(log n)
Always take the smallest/most urgentPriorityQueueoffer/poll O(log n)
Find a value by keyHashMapget/put O(1) average
Keys in sorted orderTreeMapget/put O(log n)

Fixed, unmodifiable and immutable

import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<Integer> fixed = Arrays.asList(1, 2, 3);   // fixed size: set OK, add not
        fixed.set(0, 9);
        System.out.println(fixed);

        List<Integer> frozen = List.of(1, 2, 3);        // Java 9+: fully immutable
        try {
            frozen.add(4);
        } catch (UnsupportedOperationException e) {
            System.out.println("List.of can't change");
        }
        System.out.println(Collections.max(frozen) + " " + Collections.frequency(List.of("a", "b", "a"), "a"));
    }
}
[9, 2, 3] List.of can't change 3 2

Rule of thumb: declare variables with the interface type (List<String> log = new ArrayList<>()). Your code then depends only on the promise, and you can switch to another class later by changing one word.

4 Step by step

Picking a collection in four questions

  1. Do I look things up by a key?

    Yes → a Map. Price by dish, student by roll number, count by word. Then choose: any order (HashMap), insertion order (LinkedHashMap), sorted keys (TreeMap).
  2. Must every element be unique?

    Yes → a Set. The set uses equals/hashCode (Lesson 10.3) or compareTo (TreeSet) to spot duplicates.
  3. Do I process items in arrival or priority order?

    Yes → a Queue/Deque. FIFO tokens: ArrayDeque with offer/poll. Undo stack: ArrayDeque with push/pop. Most urgent first: PriorityQueue.
  4. Otherwise: a List

    ArrayList covers most cases: fast reads by index and fast adds at the end. Lesson 11.4 shows when LinkedList is (rarely) better.
  5. Declare the interface, create the class

    Map<String, Integer> price = new HashMap<>();
    The variable's type is the interface; the object is the class. Behind the scenes the variable is just a reference to a HashMap object on the heap, which itself holds references to the key and value objects.
5 See it happen

One family, many members: both views

Left: code creating different collections. Right: where each class sits in the interface family.

Where each collection fits 6 steps
What you see Collection<String> c = …; List<String> l = new ArrayList<>(); Set<String> s = new HashSet<>(); Deque<String> q = new ArrayDeque<>(); Map<String,Integer> m = new HashMap<>(); Collections.sort(l); the common root: add, remove, size, contains ordered, index, duplicates allowed unique elements only work at both ends: queue or stack key → value, not a Collection a utility class, not the interface Interface on the left… …class on the right. A Set promises uniqueness. A Deque promises two open ends. A Map stores pairs. Collections with an s. myphatshala.in
Behind the screen Iterable Collection List Set Queue/Deque ArrayListLinkedList HashSetLinkedHashSet, TreeSet ArrayDequePriorityQueue Map → HashMap, TreeMap Collections (utility class) Collection extends Iterable: for-each works. ArrayList keeps the List promise. HashSet keeps the Set promise. ArrayDeque keeps the Deque promise. Map stands apart from Collection. Static helpers for any collection. myphatshala.in
6 Real-world use

Collections in real systems

Nearly every Java program uses collections; the skill is choosing the one whose promise matches the job.

Watch it with an example: a bank's customer-service desk

One morning at a bank branch, four collections work together: a queue of tokens, a set of customers seen today, a map of account balances, and a list of the day's log.

A morning at the help desk 5 steps
Animated example Queue: tokens T1 T2 T3 T2 T3 T3 (empty) Set: seen today {} {Riya} {Riya, Kabir} {Riya, Kabir} Riya again: add → false Map: balance Riya → ₹8,200 Kabir → ₹1,050 List: today's log [] [T1 Riya] [T1 Riya, T2 Kabir] [T1 Riya, T2 Kabir, T3 Riya] Three customers take tokens. Token 1: Riya. Look up her balance. Token 2: Kabir. Token 3: Riya again; the set doesn't grow. Report: 3 visits, 2 customers. myphatshala.in
cart: [pen, book, pen]

1. Shopping carts and feeds: List

A cart, a timeline of posts, a train's list of stations: order matters and repeats are allowed. ArrayList is the usual choice.

add to cart→List.add→shown in order

2. De-duplication and membership: Set

Unique visitors, blocked card numbers, already-processed transaction IDs (so a retried payment isn't charged twice).

txn id→processed.add(id)→false = duplicate, skip

3. Work waiting its turn: Queue

Support tickets, print jobs, messages waiting to be sent, emergency patients by severity (PriorityQueue), and browser back/undo stacks (Deque).

new ticket→queue.offer→agent calls poll()
"SBIN0001234" → SBI, Kharghar

4. Lookups and caches: Map

IFSC code → branch, user ID → session, product ID → stock. Caches that avoid slow database calls are maps at heart.

IFSC→branches.get(code)→branch details

Examples are simplified. Multi-threaded systems use the concurrent versions (ConcurrentHashMap, BlockingQueue), covered in Module 12.

7 Run the code

Canteen day, four collections

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Map<String, Integer> price = new HashMap<>();
        price.put("chai", 15);
        price.put("dosa", 60);
        price.put("vada", 25);

        List<String> orders = new ArrayList<>();
        Set<String> customers = new HashSet<>();
        Queue<String> tokens = new ArrayDeque<>();

        String[][] today = {{"Riya", "chai"}, {"Kabir", "dosa"}, {"Riya", "vada"}};
        for (String[] t : today) {
            orders.add(t[1]);
            customers.add(t[0]);
            tokens.offer(t[0] + ":" + t[1]);
        }

        int total = 0;
        for (String dish : orders) total += price.get(dish);

        System.out.println("Orders: " + orders);
        System.out.println("Customers: " + customers.size());
        System.out.println("Serve first: " + tokens.poll());
        System.out.println("Takings: ₹" + total);
    }
}
Orders: [chai, dosa, vada] Customers: 2 Serve first: Riya:chai Takings: ₹100
  • Map<String, Integer> priceLookup by dish name: price.get("dosa").
  • Set<String> customersRiya is added twice but counted once.
  • Queue<String> tokensoffer joins the back, poll serves the front.
  • Interface on the leftEach variable is declared with its interface; the class is chosen once, on the right.
8 Line by line

Same names, three containers, three results

This trace is recorded from the real JVM. Watch the heap: the list keeps every visit, the set ignores the repeat, and the map turns the repeat into a count.

Worked examples: real problems, solved and traced in memory

Three everyday problems, each solved by picking the right collection. Watch how differently they grow on the heap.

Example 1Analytics · Set

Unique visitors from a page log

Problem statement

A website logs one user ID per page view. Count unique visitors and print them in the order they first appeared.

Input
["u7", "u3", "u7", "u9", "u3"]
Expected output
3 unique: [u7, u3, u9]

Approach

  1. A LinkedHashSet ignores repeats and remembers first-arrival order.
  2. A helper uniqueVisitors(String[] log) adds every ID.
  3. Print the size and the set.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

Example 2Customer service · Queue

Serve support tickets in order

Problem statement

Tickets T101, T102, T103 arrive. An agent serves two, then T104 arrives. Print who is served and who is still waiting.

Input
T101, T102, T103; serve 2; T104 arrives
Expected output
Serving T101
Serving T102
Waiting: [T103, T104]

Approach

  1. Use ArrayDeque as a FIFO queue: offer at the back, poll from the front.
  2. Serve with poll(), which returns and removes the oldest ticket.
  3. Print what remains.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

Example 3Retail · Map

Stock left after the day's sales

Problem statement

A shop starts with pens 10, books 4. Sales today: pen, book, pen. Update stock with a Map and print it.

Input
stock {pen=10, book=4}; sales pen, book, pen
Expected output
{book=3, pen=8}

Approach

  1. A TreeMap so the report prints items alphabetically.
  2. A helper sell(stock, item) reduces the count by one.
  3. Print the map.

Solution: run it live

What happens in memory, step by step

Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.

9 Quiz and revision

Check yourself

Quick revision

Lesson 11.1 in one screen

  • Framework = interfaces + implementations + algorithms (Collections class), in java.util.
  • Iterable → Collection → List (ordered, duplicates), Set (unique), Queue/Deque (processing order). Map is separate.
  • Defaults: ArrayList, HashSet, ArrayDeque, HashMap. Sorted: TreeSet, TreeMap. Insertion order: LinkedHashSet, LinkedHashMap. Priority: PriorityQueue.
  • Choose by asking: lookup by key? unique? processing order? else List.
  • Arrays.asList = fixed size; List.of/Map.of = immutable; Collections.unmodifiableList = read-only view.
  • Declare with the interface type; collections hold references only.

Interview and viva questions

Why use collections instead of arrays?

Arrays have a fixed size and no built-in operations for searching, de-duplicating or key lookup. Collections grow automatically, offer rich, tested operations and data structures with known performance, and work through common interfaces so algorithms like sorting work on many of them.

List vs Set vs Map?

A List is an ordered sequence that allows duplicates and access by index. A Set holds unique elements (order depends on the implementation). A Map stores key–value pairs with unique keys and isn't a Collection.

What is the difference between Arrays.asList, List.of and Collections.unmodifiableList?

Arrays.asList is a fixed-size view backed by the array (set allowed, add/remove not). List.of is truly immutable and rejects nulls. Collections.unmodifiableList is a read-only view of another list: if the original changes, the view shows it.

Are the standard collections thread-safe?

No. ArrayList, HashMap and friends are not synchronised. Use java.util.concurrent classes such as ConcurrentHashMap and CopyOnWriteArrayList, or synchronise access yourself (Module 12). Legacy Vector and Hashtable are synchronised but rarely used today.

What is the root interface of the framework?

Collection is the root of List, Set and Queue; it itself extends Iterable, which is what makes the for-each loop work. Map has its own root, Map.

Practice problems

Pick the collection whose promise fits the job. The last three are business tasks.

P1Easy

Remove duplicate marks

Marks {78, 91, 78, 64, 91}: print the distinct marks in sorted order.

Input
{78, 91, 78, 64, 91}
Expected output
[64, 78, 91]
Show solution and explanation
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Integer[] marks = {78, 91, 78, 64, 91};
        Set<Integer> distinct = new TreeSet<>(Arrays.asList(marks));
        System.out.println(distinct);
    }
}
[64, 78, 91]

How it works: a TreeSet drops duplicates and keeps the rest sorted.

P2Easy

Reverse a word with a stack

Push each character of "JAVA" onto an ArrayDeque stack, then pop them to print it reversed.

Input
"JAVA"
Expected output
AVAJ
Show solution and explanation
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Deque<Character> stack = new ArrayDeque<>();
        for (char c : "JAVA".toCharArray()) stack.push(c);
        StringBuilder out = new StringBuilder();
        while (!stack.isEmpty()) out.append(stack.pop());
        System.out.println(out);
    }
}
AVAJ

How it works: a stack is last-in, first-out, so popping returns characters in reverse order.

P3Easy

Collections utility methods

For the list [5, 2, 9, 2], print the max, the min, how often 2 appears, and the list sorted.

Input
[5, 2, 9, 2]
Expected output
9 2 2
[2, 2, 5, 9]
Show solution and explanation
import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<>(List.of(5, 2, 9, 2));
        System.out.println(Collections.max(nums) + " " + Collections.min(nums) + " " + Collections.frequency(nums, 2));
        Collections.sort(nums);
        System.out.println(nums);
    }
}
9 2 2 [2, 2, 5, 9]

How it works: Collections (with an s) provides static algorithms. sort needs a modifiable list, hence the copy into an ArrayList.

P4Medium

First repeated order ID

Find the first order ID that appears twice in ["A1", "B7", "C3", "B7", "A1"].

Input
["A1", "B7", "C3", "B7", "A1"]
Expected output
First repeat: B7
Show solution and explanation
import java.util.*;

public class Main {
    public static void main(String[] args) {
        String[] ids = {"A1", "B7", "C3", "B7", "A1"};
        Set<String> seen = new HashSet<>();
        for (String id : ids) {
            if (!seen.add(id)) {
                System.out.println("First repeat: " + id);
                break;
            }
        }
    }
}
First repeat: B7

How it works: add returns false when the element is already present, so the first false is the first repeat. O(n) overall.

P5Medium

Most urgent tasks first

Tasks with priorities 4, 1, 3, 2 arrive. Print them in order of priority using a PriorityQueue.

Input
4, 1, 3, 2
Expected output
[1, 2, 3, 4]
Show solution and explanation
import java.util.*;

public class Main {
    public static void main(String[] args) {
        PriorityQueue<Integer> pq = new PriorityQueue<>(List.of(4, 1, 3, 2));
        List<Integer> order = new ArrayList<>();
        while (!pq.isEmpty()) order.add(pq.poll());
        System.out.println(order);
    }
}
[1, 2, 3, 4]

How it works: poll always removes the smallest element. Printing the queue directly wouldn't show sorted order; only polling does.

P6Business problem

Branch lookup by IFSC

Store three IFSC codes with their branch names in a map, then look up SBIN0001234 and an unknown code.

Input
"SBIN0001234", "XXXX0000000"
Expected output
SBI Kharghar
Unknown IFSC
Show solution and explanation
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Map<String, String> branch = new HashMap<>();
        branch.put("SBIN0001234", "SBI Kharghar");
        branch.put("HDFC0000240", "HDFC Vashi");
        branch.put("ICIC0001520", "ICICI Panvel");
        System.out.println(branch.get("SBIN0001234"));
        System.out.println(branch.getOrDefault("XXXX0000000", "Unknown IFSC"));
    }
}
SBI Kharghar Unknown IFSC

How it works: a HashMap finds the value for a key in constant time on average, no matter how many branches are stored.

P7Business problem

Daily sales by category, sorted

Orders: (Books, 450), (Toys, 300), (Books, 200), (Electronics, 1200). Print total per category in alphabetical order.

Input
4 orders
Expected output
{Books=650, Electronics=1200, Toys=300}
Show solution and explanation
import java.util.*;

public class Main {
    public static void main(String[] args) {
        String[] cat = {"Books", "Toys", "Books", "Electronics"};
        int[] amt = {450, 300, 200, 1200};
        Map<String, Integer> totals = new TreeMap<>();
        for (int i = 0; i < cat.length; i++) {
            totals.put(cat[i], totals.getOrDefault(cat[i], 0) + amt[i]);
        }
        System.out.println(totals);
    }
}
{Books=650, Electronics=1200, Toys=300}

How it works: the map aggregates by key; TreeMap keeps keys sorted for the report.

P8Business problem

Recently viewed products

A shop shows the last 3 products a user viewed, newest first, without repeats. Views: P1, P2, P3, P2, P4.

Input
P1, P2, P3, P2, P4
Expected output
[P4, P2, P3]
Show solution and explanation
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Deque<String> recent = new ArrayDeque<>();
        for (String p : new String[]{"P1", "P2", "P3", "P2", "P4"}) {
            recent.remove(p);          // drop an older view of the same product
            recent.addFirst(p);        // newest at the front
            if (recent.size() > 3) recent.removeLast();
        }
        System.out.println(recent);
    }
}
[P4, P2, P3]

How it works: a Deque lets us add at the front and trim from the back. Removing an existing copy first avoids repeats.

Real-world scenario questions (asked in company interviews)

Collection questions in interviews are usually “which one would you use and why?” The best answers name the promise you need, then the class.

Payments · idempotencyFresher

Don't charge twice

A payment service sometimes receives the same request twice because of network retries. Each request has a txnId. Which collection would you use to make sure each transaction is processed once, and how?

The interviewer is checking: using a Set for membership and its add() result.

Show a strong answer
  • A Set<String> of processed IDs. if (!processed.add(txnId)) return "duplicate";: add returns false if the ID was already there, in O(1) on average.
  • In a real multi-server system, keep this state in a shared store (database unique key or a cache), since each server has its own memory, and use a concurrent set within one server.
  • Expire old IDs so the set doesn't grow forever.

Avoid: scanning an ArrayList with contains. It's O(n) per request and gets slower every day.

Healthcare · triageJunior

Emergency room queue

Patients arrive at a hospital emergency desk with a severity from 1 (critical) to 5. Doctors must always see the most critical patient next, and among equals, whoever came first. Which collection?

The interviewer is checking: PriorityQueue and tie-breaking.

Show a strong answer
  • A PriorityQueue<Patient> with a comparator on severity, then arrival time (a counter or timestamp) to break ties, since PriorityQueue alone isn't stable.
  • offer and poll are O(log n); peek shows the next patient.
  • If severity can change while waiting, remove and re-insert the patient.

Avoid: sorting a List after every arrival. It works, but costs O(n log n) each time.

E-commerce · reportsFresher

Category totals in alphabetical order

Finance wants daily sales per product category, printed in alphabetical order of category. Orders arrive in random order. What would you use?

The interviewer is checking: Map for aggregation, TreeMap for sorted keys.

Show a strong answer
  • Map<String, Long> totals = new TreeMap<>(); then totals.merge(category, amount, Long::sum) for each order.
  • The TreeMap keeps categories sorted, so printing it gives the report order directly.
  • If order only matters at the end and data is huge, a HashMap plus one sort at the end is also fine.

Avoid: two parallel lists of names and totals. Keeping them in sync is error-prone.

Platform · API designJunior

A getter that leaks internals

Order.getItems() returns the order's internal ArrayList. Another team calls getItems().clear() and empties real orders. How do you prevent this?

The interviewer is checking: unmodifiable views and defensive copies.

Show a strong answer
  • Return Collections.unmodifiableList(items) (a read-only view) or List.copyOf(items) (an immutable snapshot).
  • Offer intention-revealing methods like addItem/removeItem that enforce business rules.
  • Declare the return type as List, not ArrayList, so you're free to change the implementation.

Avoid: documenting “please don't modify”. Make it impossible instead.