Classic collection traps

Collections · lesson 14 of 42 · 4 min read

Recognise the four bugs that catch almost every Java developer at least once.

Open this lesson in the learning hub

Key points

  • Arrays.asList returns a fixed-size list backed by the array. set works; add throws.
  • To get a real mutable list write new ArrayList<>(Arrays.asList(...)).
  • List<Integer>.remove(1) removes index 1. To remove the value, write remove(Integer.valueOf(1)).
  • Arrays.asList(intArray) gives a list of one element: the array. Use Arrays.stream(a).boxed().toList().
  • Mixing boxed types fails silently: Set<Short>.remove(anInt) boxes to Integer and matches nothing.
  • remove and contains take Object, not the element type, so the compiler cannot warn you.

Example

import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<String> asList = Arrays.asList("a", "b", "c");
        asList.set(0, "A");
        System.out.println("asList.set       : " + asList + "   (writes through to the array)");
        try {
            asList.add("d");
        } catch (UnsupportedOperationException e) {
            System.out.println("asList.add       : UnsupportedOperationException (fixed size)");
        }

        List<Integer> ids = new ArrayList<>(List.of(10, 20, 30));
        ids.remove(1);
        System.out.println("remove(1)        : " + ids + "   (index 1 -> dropped 20)");
        ids.remove(Integer.valueOf(30));
        System.out.println("remove(valueOf)  : " + ids + "   (object 30 -> dropped 30)");

        int[] prims = {1, 2, 3};
        System.out.println("asList(int[])    : size " + Arrays.asList(prims).size() + "   (one element: the array itself)");
        System.out.println("boxed properly   : " + Arrays.stream(prims).boxed().toList());

        Set<Short> shorts = new HashSet<>();
        for (short i = 0; i < 5; i++) {
            shorts.add(i);
            shorts.remove(i - 1);
        }
        System.out.println("Short set size   : " + shorts.size() + "   (i-1 is an int, so remove never matches)");
    }
}

When remove behaves oddly, check whether you passed an index, a value, or the wrong boxed type.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Collections course, and every lesson in it is listed on the Collections contents page.