Skip to content
CodeKruPro

Predict the output · Java

Collections

Lists, sets and maps: order, duplicates, removal and missing keys.

Learn: Predicting what Java collections print7 minute read

Collections are the classes that hold groups of values: lists, sets and maps. Test code uses them constantly, for test data, expected results and API responses. Collection questions test whether you know what each type promises (order, duplicates, what happens with a missing value) and a few method traps that cause real bugs. These rules cover nearly all of them.

Lists keep order and allow duplicates

A List keeps elements in insertion order (the order in which you added them), indexed from 0, and allows duplicates. The type in angle brackets, as in List<Integer>, says what the list holds: here, Integer values. It has two remove methods: remove(int index) and remove(Object value). The compiler picks one from the argument's type. On a List<Integer>, remove(1) passes an int, so it removes by position. To remove the value 1, pass Integer.valueOf(1), which makes an Integer object (see Numbers and arithmetic for boxed numbers).

Sets drop duplicates

A Set holds each value once. add returns true when the set changed and false for a duplicate, without any error. A HashSet promises no order, so you cannot predict its printed order from the code. A LinkedHashSet keeps insertion order and a TreeSet keeps sorted order. A TreeSet also offers first(), last() and headSet(x), which holds the values strictly below x.

Maps replace values for an existing key

A map holds one value per key. put on an existing key replaces the value and returns the old one; for a new key it returns null. get on a missing key returns null; getOrDefault returns the default you give. Ordering follows the same pattern as sets: HashMap promises none, LinkedHashMap keeps insertion order (replacing a value does not move the key), and TreeMap sorts by key. A key is the name you look a value up by, and an entry is one key with its value.

import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<>(List.of(5, 6, 7));
        nums.remove(0);
        nums.remove(Integer.valueOf(7));
        System.out.println(nums);
        Set<String> seen = new TreeSet<>(List.of("b", "a", "b"));
        System.out.println(seen + " " + seen.add("a"));
        Map<String, Integer> m = new LinkedHashMap<>();
        m.put("x", 1);
        System.out.println(m.put("x", 2) + " " + m + " " + m.get("y"));
    }
}
[6]
[a, b] false
1 {x=2} null

Sorting and counting

Natural order for strings compares character codes, so every capital letter comes before every lower-case letter. Use String.CASE_INSENSITIVE_ORDER for alphabetical order. Java's list sort is stable: equal elements keep their order. To count things, map.merge(key, 1, Integer::sum) stores 1 for a new key and adds 1 to an existing one (Integer::sum is a short way to name the method that adds two numbers).

import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>(List.of("bob", "Al", "Dave"));
        Collections.sort(names);
        System.out.println(names);
        Map<String, Integer> counts = new TreeMap<>();
        for (String w : List.of("b", "a", "b")) {
            counts.merge(w, 1, Integer::sum);
        }
        System.out.println(counts);
    }
}
[Al, Dave, bob]
{a=1, b=2}

Duplicates are decided by equals and hashCode

Hash-based sets and maps use hashCode (a number computed from an object, used to find it quickly) and equals (the check for "same content") to spot an existing element. A class that does not override them (write its own versions) treats every object as different, so two equal-looking objects both get added, and contains with a new equal-looking object returns false. Records, strings and wrapper types already compare by value. Sorted collections use compareTo or a Comparator instead; both are ways to say which of two values comes first.

Some lists cannot change size

List.of(...) returns a list that cannot be changed at all: add, remove and set throw UnsupportedOperationException, an error that stops the program. Arrays.asList(array) returns a fixed-size view of the array (a list that shows the array's data without holding its own copy): set works and writes into the array, but add and remove throw. Wrap either in new ArrayList<>(...) for a normal list.

Do not change a list inside its for-each loop

A for-each loop (for (String s : list)) uses an iterator behind the scenes. An iterator is an object that walks over the items one by one. Adding or removing through the list itself makes the iterator throw ConcurrentModificationException on its next step. One case confuses people: removing the second-to-last element ends the loop quietly, because the size check in hasNext() fails first, and the last element is never visited. Use removeIf or Iterator.remove().

import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<>(List.of(1, 2, 3, 4));
        nums.removeIf(n -> n % 2 == 0);
        System.out.println(nums);
        List<Integer> fixed = List.of(1, 2);
        try {
            fixed.add(3);
        } catch (UnsupportedOperationException e) {
            System.out.println("List.of is read-only");
        }
    }
}
[1, 3]
List.of is read-only

How to answer in an interview

Name the collection's promise before you trace: "It is a TreeMap, so the keys print sorted." For a trap, say the output and the reason, then the safe alternative, for example "it throws ConcurrentModificationException; I would use removeIf". That last part shows you would write correct test code, not only predict output.

Common mistakes

  • Predicting an order for a HashSet or HashMap.
  • Reading remove(1) on a list of numbers as "remove the value 1".
  • Expecting get on a missing key to throw.
  • Putting objects without equals and hashCode into a HashSet.
  • Calling add on a list from List.of or Arrays.asList.

Recap

Lists keep order and duplicates, sets drop duplicates, and maps keep one value per key. Hash collections promise no order, linked ones keep insertion order and tree ones sort. Equality comes from equals and hashCode. Some lists are read-only or fixed-size, and you should never change a list inside its own for-each loop.

11 questions0/11 solved

StatusQuestionDifficultyAsked in
Not startedAdding a duplicate to a SetEasy
Not startedPutting the same key twice in a MapEasy
Pro+list.remove(1): index or value?Easy-Medium
Pro+A TreeSet built from a list with repeatsEasy-Medium
Pro+TreeMap order versus LinkedHashMap orderMediumAsked in: Capgemini, Wipro
Pro+Counting words with merge and getOrDefaultMediumAsked in: Capgemini, ISS STOXX
Pro+Sorting strings with different casesMedium
Pro+Arrays.asList: write-through and fixed sizeMediumAsked in: Capgemini, Wipro
Pro+Removing from a list inside for-eachMedium-HardAsked in: Capgemini, Wipro
Pro+A HashSet of objects without equals and hashCodeMedium-HardAsked in: Cognitree, Deloitte
Pro+Removing the second-to-last element in for-eachHard
Not startedNot startedIn progressIn progressSolvedSolvedPro+Pro+

The first 2 questions of each topic are free. Pro+ opens every question.

Back to the plan