List — ArrayList & LinkedList

লিস্ট — Java-র সবচেয়ে বেশি ব্যবহৃত collection; কবে কোনটি ব্যবহার করবেন

Read: ~35 min Intermediate 5 practice problems Live code runner

1. The List Interface

List<T> is Java's ordered, index-accessible, duplicate-allowing collection contract. Every real implementation — ArrayList, LinkedList, CopyOnWriteArrayList, Vector — implements the same interface. That is the power of the Collections Framework: you code against List, and swap the implementation later if the performance profile changes.

List<T> হলো Java-র ordered, index-ভিত্তিক, duplicate-allowed collection-এর contract। ArrayList, LinkedList, Vector, CopyOnWriteArrayList — সবাই একই interface implement করে। সাধারণভাবে List-এর বিরুদ্ধে code লিখুন, দরকারে implementation পরে বদলে দিন।
Rule of thumb: Use ArrayList 99% of the time. LinkedList exists mainly to serve as a Deque.

৯৯% ক্ষেত্রে ArrayList-ই সঠিক। LinkedList আজকাল প্রধানত Deque implementation হিসেবে ব্যবহৃত।

2. ArrayList — The Default Choice

ArrayList wraps a growable array. Random access get(i) is O(1), add at the end is amortized O(1), and iteration is cache-friendly. The only weakness is insertion/removal in the middle — those are O(n) because elements must shift.

ArrayList-এর ভেতরে growable array। get(i) = O(1), শেষে add = amortized O(1), iteration cache-friendly। মাঝখানে insert/remove O(n) — কারণ element গুলো shift করতে হয়।
Main.java
import java.util.*;

class Main {
    public static void main(String[] args) {
        List<String> cities = new ArrayList<>();
        cities.add("Dhaka");
        cities.add("Chattogram");
        cities.add("Sylhet");
        cities.add(1, "Khulna");        // insert at index 1

        System.out.println(cities);
        System.out.println("size = " + cities.size());
        System.out.println("get(2) = " + cities.get(2));

        cities.remove("Sylhet");
        System.out.println("after remove: " + cities);
    }
}

3. LinkedList — Doubly-Linked Nodes

LinkedList is a doubly-linked list of node objects. addFirst/addLast and removeFirst/removeLast are all O(1), but get(i) requires walking from one end — O(n). Each node also costs extra memory for two pointers.

LinkedList হলো doubly-linked list। দুই প্রান্তে add/remove = O(1), কিন্তু get(i) = O(n) কারণ একদিক থেকে হাঁটতে হয়। প্রতিটি node-এর দুটি pointer-এর জন্য বাড়তি memory খরচ।
ArrayList — contiguous A B C D get(i) = O(1) LinkedList — nodes + pointers A B C D get(i) = O(n) Same interface · Different memory layout · Different speed profile Figure 23.1 — একই List interface, ভিতরে ভিন্ন memory layout।

4. Iterators & ConcurrentModificationException

Modifying a list while iterating with a for-each loop throws ConcurrentModificationException. The safe way to remove during iteration is to use the Iterator explicitly and call iterator.remove(), or to use the List.removeIf(predicate) method.

for-each loop চলাকালীন list modify করলে ConcurrentModificationException (CME) হয়। নিরাপদ উপায় — Iterator-এর remove() কল করা অথবা list.removeIf(predicate) ব্যবহার।
Main.java
import java.util.*;

class Main {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6));

        // Option A: Iterator.remove()
        Iterator<Integer> it = nums.iterator();
        while (it.hasNext()) {
            if (it.next() % 2 == 0) it.remove();
        }
        System.out.println("after iterator.remove: " + nums);

        // Option B: removeIf (Java 8+)
        List<Integer> xs = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6));
        xs.removeIf(n -> n % 2 == 0);
        System.out.println("after removeIf: " + xs);
    }
}

5. List.of(...) — Immutable Lists

Since Java 9, List.of(a, b, c) creates a compact, immutable list. Attempting to add, remove, or set throws UnsupportedOperationException. Use it for constants and defensive copies.

Java 9 থেকে List.of(...) immutable list দেয়। add/remove/set করলে UnsupportedOperationException হবে। Constant বা defensive copy-র জন্য উপযুক্ত।
Main.java
import java.util.*;

class Main {
    public static void main(String[] args) {
        List<String> fixed = List.of("red", "green", "blue");
        System.out.println(fixed);
        try {
            fixed.add("yellow");
        } catch (UnsupportedOperationException ex) {
            System.out.println("Cannot mutate: " + ex.getClass().getSimpleName());
        }
    }
}

6. Complexity & Vocabulary

OperationArrayListLinkedListবাংলায়
get(i)O(1)O(n)ArrayList-ই দ্রুত।
add(e) at endAmortized O(1)O(1)উভয়েই দ্রুত।
add(0, e) at frontO(n)O(1)LinkedList জেতে।
remove(i) middleO(n) shiftO(n) walkদুটিই ধীর।
Memory overheadLowHigh (2 pointers/node)ArrayList হালকা।
Cache friendlinessExcellentPoorArrayList স্পষ্ট এগিয়ে।

7. Practice Problems

  1. Create an ArrayList<String> of five colors and print them in reverse order.
    পাঁচটি রং-এর একটি ArrayList<String> বানিয়ে উল্টো ক্রমে প্রিন্ট করুন।
    ✨ Show Answer
    Main.java
    import java.util.*;
    class Main {
        public static void main(String[] args) {
            List<String> colors = new ArrayList<>(List.of("red", "green", "blue", "yellow", "pink"));
            Collections.reverse(colors);
            System.out.println(colors);
        }
    }
  2. Remove all odd numbers from a list of 1..10 using removeIf.
    1..10 list থেকে সব বিজোড় সংখ্যা removeIf দিয়ে মুছুন।
    ✨ Show Answer
    Main.java
    import java.util.*;
    class Main {
        public static void main(String[] args) {
            List<Integer> xs = new ArrayList<>();
            for (int i = 1; i <= 10; i++) xs.add(i);
            xs.removeIf(n -> n % 2 != 0);
            System.out.println(xs);
        }
    }
  3. Explain the amortized O(1) cost of ArrayList.add at the end.
    ArrayList.add-এ amortized O(1) মানে কী — ব্যাখ্যা করুন।
    ✨ Show Answer

    Answer: The backing array grows by roughly 1.5× when full. Most add calls are just one slot assignment — O(1). Occasionally the array doubles/grows, which costs O(n). Spread across n adds, total work is O(n), so the average per operation is O(1) — that is what "amortized" means.

    ভিতরের array ~1.5× করে বাড়ে। বেশির ভাগ add শুধু একটি index-এ value বসানো — O(1)। কখনো কখনো array-কে resize করতে হয় (O(n)), কিন্তু n-সংখ্যক add-এ মোট O(n), তাই গড়ে প্রতিটি = O(1) — এটাই amortized।

  4. Show a safe way to remove all empty strings from a List<String> while iterating.
    iterating অবস্থায় List<String> থেকে সব empty string নিরাপদে মুছুন।
    ✨ Show Answer
    Main.java
    import java.util.*;
    class Main {
        public static void main(String[] args) {
            List<String> xs = new ArrayList<>(List.of("a", "", "b", "", "c"));
            Iterator<String> it = xs.iterator();
            while (it.hasNext()) {
                if (it.next().isEmpty()) it.remove();
            }
            System.out.println(xs);
        }
    }
  5. Give one scenario where LinkedList is genuinely the better choice.
    কোন এক পরিস্থিতিতে LinkedList সত্যিই ভালো — ব্যাখ্যা করুন।
    ✨ Show Answer

    Answer: Use LinkedList as a Deque when you frequently add/remove from both ends — for example, a fixed-size recent-history buffer where each event is pushed at the front and old events drop off the back. Even here, most modern code uses ArrayDeque, which beats LinkedList for cache friendliness and speed. So in real practice, LinkedList's niche is small.

    দুই প্রান্তে বারবার add/remove হলে (যেমন recent-history buffer)। তবে সেক্ষেত্রেও আধুনিক code সাধারণত ArrayDeque বেছে নেয় — cache-friendly এবং দ্রুত। তাই LinkedList-এর প্রকৃত ব্যবহারিক ক্ষেত্র খুব সীমিত।

Summary — Module 23

List<T> is Java's ordered, indexable, duplicate-allowed collection. ArrayList is the default — fast random access and tight memory. LinkedList wins only when you need cheap add/remove at both ends. Mutate safely with Iterator.remove() or removeIf(...). Use List.of(...) for immutable constants.

List<T> Java-র ordered, index-ভিত্তিক, duplicate-allowed collection। ArrayList default — দ্রুত random access এবং কম memory। LinkedList শুধু দুই প্রান্তে add/remove-এ ভালো। Iterator.remove() বা removeIf() দিয়ে safely modify করুন। Constant-এর জন্য List.of(...)।

Next Module → Map — HashMap, TreeMap, LinkedHashMap।