RadhaPublication
HomeInterviewLearning PathsRole TracksMockBooksPricing
Login / Sign UpLog in

© 2026 Radha Publication. All rights reserved.

Shop on AmazonDonateContactPrivacyTerms
Java questions
MediumJava#276 min readJul 11, 2026

List vs Set vs Queue.

practice
learning
Practice modeTest yourself instead of reading straight through

Three common collections, three different jobs: one keeps order, one enforces uniqueness, and one processes work in line. Interviewers love this because it checks whether you choose the right tool instead of just naming classes.

Question: List vs Set vs Queue.

Answer: A List stores elements in order and allows duplicates, so you can access items by index. A Set stores unique elements only, so duplicates are rejected based on equals() and hashCode(). A Queue is for processing elements in a flow, usually first-in-first-out, where you add at one end and remove from the other.

Interview-Ready Answer: I use a List when order and index-based access matter, a Set when I need uniqueness, and a Queue when I need to process items in arrival order. For example, ArrayList is good for fast reads by index, HashSet gives average O(1) membership checks, and ArrayDeque is a strong choice for a FIFO queue because enqueue and dequeue are typically O(1). The key difference is not just the data structure name, but the rule it enforces: order, uniqueness, or processing order.

🧠 Memory Map
Memory map — visual summary of this topic

What each one is

  1. List: an ordered sequence. Think of it like a numbered row of seats. You care about position, and duplicates are fine.
  2. Set: a collection that forbids duplicates. Think of it like a guest list: the same person should not be admitted twice.
  3. Queue: a waiting line. You usually add at the back and remove from the front, so the oldest item gets handled first.

How they work under the hood

  1. ArrayList stores elements in a resizable array. Index lookup is fast because Java can jump directly to the slot, so get(i) is O(1). Inserting or removing in the middle shifts later elements, so that is O(n). A practical detail interviewers like: ArrayList grows automatically, and expansion is amortized O(1) for appends.
  2. HashSet is backed by a HashMap. When you add an element, Java hashes it, finds a bucket, and checks equals() to see whether the value is already there. Average contains(), add(), and remove() are O(1); the worst case can degrade toward O(n) if many items collide in the same bucket. Default HashMap load factor is 0.75, which means it grows before buckets become too crowded.
  3. Queue is an interface, so behavior depends on the implementation. ArrayDeque is a common FIFO queue: it uses a circular array, so adding at the tail and removing from the head are typically O(1). PriorityQueue is different: it uses a heap, which means the next item removed is the smallest or highest-priority one, not necessarily the oldest.

Comparison table

FeatureListSetQueue
OrderYesUsually noUsually FIFO
DuplicatesAllowedNot allowedAllowed
Index accessYesNoNo
Typical useSequenceUniquenessProcessing
Common impl.ArrayListHashSetArrayDeque

When and why to use each

  1. Use a List when you need to preserve the exact order of items, show items in a UI, or fetch by position.
  2. Use a Set when duplicates are a bug, such as tracking unique user IDs, tags, or visited nodes.
  3. Use a Queue when tasks should be handled in arrival order, like jobs, messages, or retries.

Important edge cases

  1. Set uniqueness depends on equality. If you create your own class, you must correctly implement equals() and hashCode(), or the set may treat equal objects as different.
  2. Queue does not always mean FIFO. A PriorityQueue is still a queue, but it removes by priority, not by arrival time.
  3. Null handling differs by implementation. ArrayList allows nulls, HashSet allows one null, and ArrayDeque rejects null because null is also used as a signal for an empty poll.
  4. Choose the implementation, not just the interface. A List interface does not guarantee fast access; LinkedList and ArrayList behave very differently.

Memory hook

One line to remember: List = lane, Set = filter, Queue = line. Lane means ordered positions, filter means no duplicates pass through, and line means first come, first served.

Real-World Example: Imagine a checkout service in an e-commerce system. The service may keep a List of cart items because the order of items is shown to the customer, a Set of coupon codes or product IDs to avoid duplicates, and a Queue of payment retry jobs so failed payments are retried in arrival order.

What goes wrong when teams confuse these? If a developer uses a Set for cart items, two identical products collapse into one and the customer sees the wrong quantity. If they use a List where uniqueness is required, duplicate retries or duplicate notifications can be sent. If they use the wrong queue type, urgent jobs may get stuck behind old ones, or a priority-sensitive workflow may process the wrong task first.

Symptoms you would see: duplicate database writes, missing line items in the UI, retry logs showing the same order being processed twice, and support tickets saying the cart total or notification count is wrong. In production, these bugs are painful because the code still runs; it just quietly breaks business rules.

Java
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Queue;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        // LIST: keep order and allow duplicates.
        List<String> list = new ArrayList<>();
        list.add("apple");
        list.add("banana");
        list.add("apple"); // duplicate is allowed
        list.add(null);      // ArrayList allows null

        System.out.println("List contents: " + list);
        System.out.println("List[1]: " + list.get(1));
        System.out.println("List size: " + list.size());

        // SET: keep only unique values.
        Set<String> set = new HashSet<>();
        set.add("apple");
        set.add("banana");
        set.add("apple"); // ignored because it is already present
        set.add(null);      // HashSet allows one null

        System.out.println("Set contents: " + set);
        System.out.println("Set contains 'apple': " + set.contains("apple"));
        System.out.println("Set size: " + set.size());

        // QUEUE: process items in arrival order.
        Queue<String> queue = new ArrayDeque<>();
        queue.offer("job-1");
        queue.offer("job-2");
        queue.offer("job-3");

        System.out.println("Queue peek (no removal): " + queue.peek());
        System.out.println("Queue poll (removes head): " + queue.poll());
        System.out.println("Queue after poll: " + queue);

        // Edge case: polling an empty queue returns null instead of throwing.
        queue.poll();
        queue.poll();
        System.out.println("Poll on empty queue: " + queue.poll());

        // Failure path: ArrayDeque rejects null because null would be ambiguous.
        try {
            queue.offer(null);
        } catch (NullPointerException e) {
            System.out.println("ArrayDeque rejects null: " + e.getClass().getSimpleName());
        }

        // Mini summary to reinforce the mental model.
        System.out.println("\nSummary:");
        System.out.println("List = ordered, duplicates allowed, index-based access");
        System.out.println("Set = unique values only");
        System.out.println("Queue = process in line order");
    }
}

Follow-up & Tricky Questions:

  • What is the difference between HashSet, LinkedHashSet, and TreeSet?
    HashSet is fastest on average and does not promise order, LinkedHashSet keeps insertion order, and TreeSet keeps elements sorted using a tree, so operations are usually O(log n).
  • Why would you choose ArrayDeque over LinkedList for a queue?
    ArrayDeque is usually faster and more memory-friendly for queue and stack-like use because it uses a resizable array instead of storing one node object per element.
  • What methods should you prefer on a Queue?
    Prefer offer(), poll(), and peek() because they are safer: they return special values instead of throwing exceptions in common empty/full situations.
  • Why does HashSet need hashCode() and equals()?
    hashCode() helps find the bucket quickly, and equals() confirms whether two objects are truly the same value. If they do not match the contract, the set can store duplicates that should have been equal.
  • Can a Queue contain duplicates?
    Yes. A queue controls processing order, not uniqueness, so duplicate tasks are allowed unless your application adds its own de-duplication rule.
  • Gotcha: Does Queue always mean FIFO?
    No. A PriorityQueue removes the highest-priority item first, so it is a queue but not a simple first-in-first-out line.
  • Gotcha: Can every set contain null?
    No. HashSet allows one null, but sorted sets like TreeSet typically reject null because they need to compare elements.
  • Gotcha: Is List always fast for lookup?
    No. ArrayList is fast for index lookup, but a LinkedList is not; interface choice does not guarantee performance.

Common Mistakes:

  • Using Set for ordered data. Correction: choose List if position matters, or LinkedHashSet only if you need uniqueness plus insertion order.
  • Assuming Queue always means FIFO. Correction: check the implementation; PriorityQueue is ordered by priority.
  • Forgetting equals() and hashCode() on custom objects in a set. Correction: implement both consistently so duplicates are detected properly.
  • Talking only about interfaces, not implementations. Correction: mention ArrayList, HashSet, and ArrayDeque, because real performance comes from the implementation.

Memory Hook: List = lane, Set = filter, Queue = line. Lane keeps positions, filter blocks duplicates, line processes whoever arrived first.

Cheat Sheet:

  • List = ordered, duplicates allowed, index access.
  • Set = unique values only, no duplicate entries.
  • Queue = process items in arrival order, usually with offer/poll/peek.
  • ArrayList is great for fast reads by index.
  • HashSet gives average O(1) membership checks.
  • ArrayDeque is a strong default queue implementation.

Practice Tasks:

  • Create a List of book titles and print the third item.
  • Create a Set of emails and prove duplicates are removed.
  • Create a Queue of tasks and process them until empty, then test what happens when you poll again.
Previous
Back to Questions←→to navigate
Next

Recommended Resources

Recommended Book

Cracking the Coding Interview

189 Programming Questions and Solutions

Recommended Book

Cracking the Coding Interview

189 Programming Questions and Solutions

import java.util.ArrayDeque; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Queue; import java.util.Set; public class Main { public static void main(String[] args) { // LIST: keep order and allow duplicates. List<String> list = new ArrayList<>(); list.add("apple"); list.add("banana"); list.add("apple"); // duplicate is allowed list.add(null); // ArrayList allows null System.out.println("List contents: " + list); System.out.println("List[1]: " + list.get(1)); System.out.println("List size: " + list.size()); // SET: keep only unique values. Set<String> set = new HashSet<>(); set.add("apple"); set.add("banana"); set.add("apple"); // ignored because it is already present set.add(null); // HashSet allows one null System.out.println("Set contents: " + set); System.out.println("Set contains 'apple': " + set.contains("apple")); System.out.println("Set size: " + set.size()); // QUEUE: process items in arrival order. Queue<String> queue = new ArrayDeque<>(); queue.offer("job-1"); queue.offer("job-2"); queue.offer("job-3"); System.out.println("Queue peek (no removal): " + queue.peek()); System.out.println("Queue poll (removes head): " + queue.poll()); System.out.println("Queue after poll: " + queue); // Edge case: polling an empty queue returns null instead of throwing. queue.poll(); queue.poll(); System.out.println("Poll on empty queue: " + queue.poll()); // Failure path: ArrayDeque rejects null because null would be ambiguous. try { queue.offer(null); } catch (NullPointerException e) { System.out.println("ArrayDeque rejects null: " + e.getClass().getSimpleName()); } // Mini summary to reinforce the mental model. System.out.println("\nSummary:"); System.out.println("List = ordered, duplicates allowed, index-based access"); System.out.println("Set = unique values only"); System.out.println("Queue = process in line order"); } }