Iterator and Collections Utility

Removing While Iterating

Example

Removing from a list inside a for-each loop throws ConcurrentModificationException. Use Iterator.remove() or removeIf.

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> scores = new ArrayList<>(List.of(45, 82, 30, 91, 28, 77));

        try {
            for (Integer s : scores) {
                if (s < 40) scores.remove(s);
            }
        } catch (java.util.ConcurrentModificationException e) {
            System.out.println("for-each + remove -> ConcurrentModificationException");
        }

        scores = new ArrayList<>(List.of(45, 82, 30, 91, 28, 77));
        Iterator<Integer> it = scores.iterator();
        while (it.hasNext()) {
            if (it.next() < 40) {
                it.remove();                     // safe
            }
        }
        System.out.println("After iterator.remove: " + scores);

        List<Integer> more = new ArrayList<>(List.of(12, 55, 39, 60));
        more.removeIf(s -> s < 40);              // shortest and safest
        System.out.println("After removeIf: " + more);
    }
}

Output

for-each + remove -> ConcurrentModificationException
After iterator.remove: [45, 82, 91, 77]
After removeIf: [55, 60]

The Collections Class

Example

java.util.Collections has static helpers for sorting, searching, shuffling and wrapping collections.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class Main {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<>(List.of(5, 3, 9, 1, 7));
        Collections.sort(nums);
        System.out.println("sorted     " + nums);
        System.out.println("binary search 7 -> index " + Collections.binarySearch(nums, 7));
        Collections.reverse(nums);
        System.out.println("reversed   " + nums);
        System.out.println("max/min    " + Collections.max(nums) + "/" + Collections.min(nums));
        Collections.swap(nums, 0, 4);
        System.out.println("swapped    " + nums);
        Collections.shuffle(nums, new Random(42));      // seeded, so the output is repeatable
        System.out.println("shuffled   " + nums);
        System.out.println("frequency  " + Collections.frequency(List.of("a", "b", "a"), "a"));
        System.out.println("nCopies    " + Collections.nCopies(3, "-"));
        List<Integer> locked = Collections.unmodifiableList(nums);
        System.out.println("read-only? " + (locked != nums));
    }
}

Output

sorted     [1, 3, 5, 7, 9]
binary search 7 -> index 3
reversed   [9, 7, 5, 3, 1]
max/min    9/1
swapped    [1, 7, 5, 3, 9]
shuffled   [7, 5, 3, 9, 1]
frequency  2
nCopies    [-, -, -]
read-only? true

Practice

Exercise: Given a List<String> of email addresses with duplicates and mixed case, return a sorted list of unique lower-case emails.

Show answer
static List<String> cleanEmails(List<String> emails) {
    Set<String> unique = new TreeSet<>();
    for (String e : emails) {
        unique.add(e.strip().toLowerCase());
    }
    return new ArrayList<>(unique);
}