SaveMyCert
Log in
5 of 5 free questions left today·for 30 a day
Using Arrays and Collections to Store and Retrieve Data

Java Arrays and Collections: List, Set, Map, Deque and Sequenced Collections (1Z0-831)

22 min read1Z0-831 · Using Arrays and Collections to Store and Retrieve DataUpdated

Java arrays and the Collections Framework are the two ways a program stores groups of values: an array is a fixed-length, indexed block of elements, while List, Set, Map and Deque are resizable interfaces from java.util with distinct rules for order, duplicates and lookup. Oracle 1Z0-831 objective 5.1 asks you to create each of them — plus the sequenced collections added in Java 21 — and to add, remove, update, retrieve and sort their elements. This lesson covers array creation and the Arrays utility methods, the difference between modifiable, fixed-size and unmodifiable lists, list, set and map operations and their return values, sorting with Comparable and Comparator, TreeSet and TreeMap navigation, Deque stack and queue methods, and the first/last/reversed() methods of sequenced collections — with the exceptions each one can throw.

What you’ll learn
  • Create one- and multidimensional arrays, predict default values, and copy, compare, sort and search them with java.util.Arrays.
  • Distinguish ArrayList, Arrays.asList, List.of/List.copyOf and Collections.unmodifiableList by what they allow, whether they accept null and whether they follow their source.
  • Trace List, Set and Map operations by their return values, including remove(int) versus remove(Object), put, putIfAbsent, getOrDefault, merge and compute.
  • Sort collections with natural ordering and chained Comparators, and explain how equals/hashCode and compareTo decide duplicates in HashSet and TreeSet.
  • Use NavigableSet and TreeMap lookups and range views, and Deque methods as a stack and as a queue, including which methods throw and which return null.
  • Apply the SequencedCollection, SequencedSet and SequencedMap methods, including live reversed() views and the cases that throw UnsupportedOperationException.

Creating arrays: size, initializers, defaults and length

An array is a fixed-length, indexed container created either with new and a size or with an initializer list — never both. int[] a = new int[3]; and int[] b = {1, 2, 3}; compile; new int[3] {1, 2, 3} does not, and the bare-brace form {1, 2, 3} is only allowed in a declaration (elsewhere write new int[] {1, 2, 3}).

Elements of a new array always start at their default value, even inside a method where local variables have none:

Element typeDefault
byte short int long0 (0L)
float double0.0
char'\u0000'
booleanfalse
Any reference type (String, Integer, arrays)null

length is a field (no parentheses) holding the element count, so valid indexes run from 0 to length - 1. The last element is a[a.length - 1]; a[a.length] compiles but throws ArrayIndexOutOfBoundsException at runtime.

Where the brackets go

The brackets of a declaration may sit on the type, on the variable name, or be split between them, and every pair counts. int[] a and int a[] both declare an int[]; int[][] g, int g[][] and int[] g[] all declare an int[][]. In a multi-variable declaration the type-side brackets apply to every name, but name-side brackets only to their own name: int[] p, q[]; makes p an int[] and q an int[][].

Multidimensional and ragged arrays

Java has arrays of arrays. new int[3][4] builds an outer array of length 3 whose every row has length 4. new int[3][] builds only the outer array: its three rows are null until you assign them, and rows may have different lengths (a ragged array). Only the first dimension is required: new int[3][] compiles, but new int[][2] does not (the compiler reports ']' expected), because a later dimension cannot be fixed while an earlier one is unknown. Reading grid[2].length before row 2 is assigned throws NullPointerException, not ArrayIndexOutOfBoundsException. Assigning one row into another slot (grid[1] = grid[0];) makes both slots refer to the same row object — writes through one are seen through the other.

Copying, comparing, sorting and searching arrays

An array variable holds a reference, so assignment shares the array while clone() or Arrays.copyOf creates a new one. Arrays do not override equals, hashCode or toString: a.equals(b) is identity (same as ==), and printing an array shows a type code and hash such as [I@1b6d3586. Use the java.util.Arrays helpers for contents.

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] a = {5, 1, 4};
        int[] alias = a;
        int[] copy = a.clone();
        alias[0] = 9;
        System.out.println(a[0] + " " + copy[0]);
        System.out.println(a.equals(copy) + " "
            + Arrays.equals(new int[] {1}, new int[] {1}));
        Arrays.sort(a);
        System.out.println(Arrays.toString(a) + " "
            + Arrays.binarySearch(a, 4) + " "
            + Arrays.binarySearch(a, 6));
        int[][] grid = new int[3][];
        grid[0] = new int[2];
        System.out.println(grid.length + " " + grid[0].length
            + " " + grid[1]);
    }
}

Output (run on JDK 25):

9 5
false true
[1, 4, 9] 1 -3
3 2 null
MethodWhat it does
Arrays.toString(a) / deepToString(a)Element-by-element text; deepToString for nested arrays
Arrays.equals(a, b) / deepEqualstrue when same length and equal elements in order
Arrays.copyOf(a, n) / copyOfRange(a, from, to)New array; pads with defaults when n is longer; range is half-open
Arrays.sort(a) / sort(a, from, to)Sorts in place (returns void); natural order, or a Comparator for object arrays; range is from inclusive, to exclusive
Arrays.binarySearch(a, key)Index of the key in a sorted array; if absent, -(insertion point) - 1; result undefined on an unsorted array
Arrays.mismatch(a, b)First index where they differ; -1 if identical; the shorter length when one is a proper prefix of the other
Arrays.compare(a, b)Lexicographic order sign: negative, zero or positive; a proper prefix is smaller

In the output above, 6 is missing from [1, 4, 9]; its insertion point (the index of the first element greater than 6) is 2, so binarySearch returns -(2) - 1 = -3.

clone() is shallow. Cloning a 2D array copies only the outer array; both copies share the same row arrays, so copy[0][0] = 7 changes the original too, while copy[0] = new int[2] does not.

Strings sort and compare by UTF-16 code unit, which is case-sensitive: digits come before uppercase letters, which come before lowercase letters. That applies to Arrays.sort, Arrays.compare on String[], TreeSet<String> and List.sort(null) alike.

Four kinds of list: ArrayList, Arrays.asList, List.of and unmodifiable views

Lists that look the same differ in whether you can change their elements, their size, and whether they follow another object. This table is the core of many code-reading items:

Created withsetadd/removeNullsLinked to a source?
new ArrayList<>(...)YesYesAllowedNo — an independent copy
Arrays.asList(arr)YesNo — UnsupportedOperationException (fixed size)AllowedYes — writes through to the array both ways
List.of(...) / List.copyOf(c)No — UnsupportedOperationExceptionNo — UnsupportedOperationExceptionRejected — NullPointerException, even from contains(null)No — a snapshot
Collections.unmodifiableList(l)NoNoWhatever the source allowsYes — a read-only view that shows later changes to l
import java.util.*;

public class Main {
    public static void main(String[] args) {
        String[] arr = {"m", "k", "p"};
        List<String> view = Arrays.asList(arr);
        view.set(2, "a");
        arr[0] = "t";
        System.out.println(view + " " + Arrays.toString(arr));
        Collections.sort(view);
        System.out.println(Arrays.toString(arr));
        try {
            view.remove(0);
        } catch (UnsupportedOperationException e) {
            System.out.println("asList remove: UOE");
        }
        List<Integer> src = new ArrayList<>(List.of(7, 8));
        List<Integer> live = Collections.unmodifiableList(src);
        List<Integer> frozen = List.copyOf(src);
        src.remove(0);
        System.out.println(live + " " + frozen);
        try {
            List.of(3, 1, 2).sort(null);
        } catch (UnsupportedOperationException e) {
            System.out.println("List.of sort: UOE");
        }
    }
}

Output (run on JDK 25):

[t, k, a] [t, k, a]
[a, k, t]
asList remove: UOE
[8] [7, 8]
List.of sort: UOE

Sorting and sub-lists

Sorting rearranges elements without changing the size, so it follows the set column of the table: Collections.sort(view) or view.sort(null) on an Arrays.asList list succeeds and reorders the backing array too, while sort on a List.of or List.copyOf list throws UnsupportedOperationException (as does sorting an unmodifiable view). subList(from, to) returns a half-open view of the list, not a copy: creating it never changes anything and works on any list, even an unmodifiable one, but later changes through it reach the original (list.subList(0, 2).clear() removes the first two elements) and follow the original's own rules, so a mutator through a sub-list of List.of(...) throws UnsupportedOperationException.

Two traps around Arrays.asList: passing a primitive array (int[]) produces a one-element List<int[]>, because generics cannot hold primitives; and wrapping it in new ArrayList<>(Arrays.asList(arr)) makes a resizable copy that no longer writes through to arr.

Adding, updating, retrieving and removing list elements

A List is an ordered, zero-indexed collection that allows duplicates. The methods behave as follows:

  • add(e) appends and returns true; add(i, e) inserts at i and shifts later elements right. i may equal size() (append) but not exceed it.
  • set(i, e) replaces and returns the element it replaced; get(i) reads. Both require 0 <= i < size(), otherwise IndexOutOfBoundsException.
  • indexOf(o) / lastIndexOf(o) return the first / last matching index or -1; contains(o) uses equals.
  • remove(int index) removes by position and returns the element; remove(Object o) removes the first equal element and returns a boolean — false, with no exception, when nothing matches.
  • removeAll(c) removes every element that is equals to some element of c, and retainAll(c) keeps only those. Matching is whole-element equality, not a prefix or pattern: removeAll(List.of("x")) removes "x" but leaves "x1". Use removeIf(predicate) for any other condition.

With a List<Integer>, list.remove(1) picks the exact-match remove(int) overload and removes index 1; to remove the value 1, pass an object: remove(Integer.valueOf(1)). If the variable's declared type is Collection<Integer>, only remove(Object) exists, so the same call autoboxes and removes the value.

import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<>(List.of(5, 15, 25, 35));
        nums.remove(2);
        nums.remove(Integer.valueOf(5));
        System.out.println(nums);
        List<String> s = new ArrayList<>(List.of("red", "blue"));
        s.add(0, "cyan");
        String old = s.set(1, "pink");
        System.out.println(old + " " + s + " " + s.indexOf("blue"));
        s.removeIf(x -> x.startsWith("c"));
        System.out.println(s + " " + s.remove("gold"));
    }
}

Output (run on JDK 25):

[15, 35]
red [cyan, pink, blue] 2
[pink, blue] false

Removing while iterating

Changing a list's size during a for-each loop (other than through the iterator) makes the next next() call throw ConcurrentModificationException. One well-known exception: removing the second-to-last element shrinks the list so that hasNext() returns false, the loop ends quietly, and the last element is never visited. Safe ways to remove are list.removeIf(predicate) and an explicit Iterator with it.remove(). A forward index loop that calls remove(i) does not throw, but it skips the element that slides into position i.

Sorting lists with Comparable and Comparator

A list sorts either by its elements' natural order (Comparable.compareTo) or by a Comparator. list.sort(null) and Collections.sort(list) use natural order — String, the wrapper types and the date/time types are all Comparable; a class that isn't makes Collections.sort(list) fail to compile and list.sort(null) throw ClassCastException.

Comparators are built by chaining:

  • Comparator.comparing(Book::title), comparingInt(Book::pages) — sort by a key.
  • .thenComparing(...) — consulted only when the earlier comparison is a tie.
  • .reversed() — reverses the whole chain built so far, i.e. everything to its left, not what you add after it.
  • Comparator.naturalOrder() / reverseOrder(), and Collections.reverseOrder().

So with a Book record, comparing(Book::title).reversed().thenComparingInt(Book::pages) orders titles Z to A and then, among books with the same title, the shorter book first; moving .reversed() to the end of the chain would reverse both keys, putting the longer book first as well. A comparator returns a negative number, zero or a positive number; zero means "equal for ordering", which matters greatly for sorted sets and maps.

Sets: HashSet, LinkedHashSet and TreeSet

A Set holds no duplicate elements: add returns false and leaves the set unchanged when an equal element is already present, and remove returns whether anything was removed. What "equal" means depends on the implementation:

SetOrderDuplicate testNulls
HashSetNone guaranteedhashCode, then equals(Object)One allowed
LinkedHashSetInsertion order (a SequencedSet)hashCode + equalsOne allowed
TreeSetSorted (a NavigableSet)compareTo/compare returning 0Rejected with natural ordering

equals and hashCode

Hash-based collections find an element by its hash bucket first and then by equals(Object), so a class must override both consistently. Overriding only equals (or only hashCode) lets two "equal" objects both be added. A method written as equals(Point p) is an overload, not an override, and collections never call it. Records generate equals, hashCode and toString from their components, so equal records collapse to one element. Mutating a field used by hashCode while the object sits in a HashSet or as a HashMap key strands it in the wrong bucket: contains and remove then fail to find it.

TreeSet uses comparison, not equals

A TreeSet needs Comparable elements or a Comparator; adding a non-comparable element throws ClassCastException — even the very first add, because the set compares it with itself. Uniqueness comes from the comparison: elements the comparator calls equal (result 0) are duplicates even if equals disagrees. The same comparison is used for every lookup, not only for add: contains and remove find an element when the comparator returns 0, whatever its spelling. The element added first is the one kept, and a later "equal" element is simply rejected (add returns false), so the stored spelling never changes. A length comparator therefore keeps only one word per length, and a case-insensitive set keeps whichever capitalisation arrived first:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        TreeSet<Integer> t = new TreeSet<>(List.of(5, 15, 25, 35));
        System.out.println(t.ceiling(16) + " " + t.higher(25) + " "
            + t.floor(34) + " " + t.lower(5));
        System.out.println(t.headSet(25) + " " + t.tailSet(15)
            + " " + t.subSet(5, 25) + " " + t.headSet(25, true));
        Set<String> byLen =
            new TreeSet<>(Comparator.comparing(String::length));
        byLen.add("apple");
        byLen.add("kiwi");
        byLen.add("melon");
        System.out.println(byLen);
        Set<String> ci = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
        ci.add("Tea");
        System.out.println(ci.add("TEA") + " " + ci.contains("tea")
            + " " + ci);
        System.out.println(new TreeSet<>(List.of(9, 4))
            .equals(new LinkedHashSet<>(List.of(4, 9))));
    }
}

Output (run on JDK 25):

25 35 25 null
[5, 15] [15, 25, 35] [5, 15] [5, 15, 25]
[kiwi, apple]
false true [Tea]
true

The last line shows that Set.equals compares elements only: two sets are equal when they have the same size and each contains every element of the other, regardless of implementation or iteration order. A TreeSet, a LinkedHashSet, a HashSet and a Set.of(...) holding the same elements are all equal to each other (the same is true of List.equals across list types, but lists also compare order).

NavigableSet lookups and ranges

ceiling(e) is the smallest element >= e and floor(e) the largest <= e; higher and lower are the strict versions. They return null when nothing qualifies. headSet(to) excludes to, tailSet(from) includes from, and subSet(from, to) is half-open — the boolean overloads (headSet(to, true)) set inclusivity explicitly. These ranges are live views of the set. pollFirst()/pollLast() remove and return the ends (or null when empty), and descendingSet() is a reverse view.

Maps: put, get, remove, merge and compute

A Map stores key-to-value mappings with unique keys; putting an existing key replaces its value. The return values are what code-reading questions trace:

  • put(k, v) returns the previous value, or null if there was none. get(k) returns null for a missing key (and for a key mapped to null — use containsKey to tell them apart).
  • remove(k) returns the removed value; remove(k, v) removes only if currently mapped to v and returns a boolean.
  • getOrDefault(k, d) returns d only when the key is absent; a key mapped to null returns null.
  • putIfAbsent(k, v) stores v when the key is absent or mapped to null, and returns the old value.
  • merge(k, v, fn) puts v if the key is absent (or null), otherwise stores fn(old, v).
  • compute(k, fn), computeIfAbsent(k, fn) and computeIfPresent(k, fn) store the function's result.

For merge and all three compute methods, a function result of null removes the mapping (or adds nothing). computeIfAbsent(k, x -> new ArrayList<>()).add(v) is the standard idiom for grouping values under one list per key, because it returns the existing or newly stored value.

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Map<String, Integer> m = new HashMap<>();
        System.out.print(m.put("a", 1) + " ");
        System.out.print(m.put("a", 2) + " ");
        m.merge("a", 5, Integer::sum);
        m.merge("b", 5, Integer::sum);
        m.computeIfPresent("b", (k, v) -> null);
        m.computeIfAbsent("c", k -> 3);
        System.out.println(new TreeMap<>(m));
        Map<Integer, List<String>> byLen = new TreeMap<>();
        for (String w : List.of("sun", "moon", "sky", "star")) {
            byLen.computeIfAbsent(w.length(),
                k -> new ArrayList<>()).add(w);
        }
        System.out.println(byLen);
        Map<String, String> n = new HashMap<>();
        n.put("q", null);
        System.out.println(n.get("q") + " " + n.containsKey("q")
            + " " + n.putIfAbsent("q", "z") + " " + n.get("q"));
    }
}

Output (run on JDK 25):

null 1 {a=7, c=3}
{3=[sun, sky], 4=[moon, star]}
null true null z

Unmodifiable map factories

Map.of(k1, v1, …), Map.ofEntries(Map.entry(k, v), …) and Map.copyOf(m) create unmodifiable maps: every mutator (put, remove, merge…) throws UnsupportedOperationException, a null key or value throws NullPointerException (also from Map.entry), and a duplicate key in Map.of/ofEntries throws IllegalArgumentException. Their iteration order is unspecified. HashMap and LinkedHashMap allow one null key and null values; TreeMap with natural ordering rejects a null key.

Iterating and updating through views

entrySet(), keySet() and values() are live views of the map. Iterate entrySet() to read key and value together; entry.setValue(v) updates the map, and removing through a view (values().remove(x), keySet().removeIf(...)) deletes the whole entry. Views cannot add: keySet().add(k) throws UnsupportedOperationException, since there is no value. Reassigning the loop variable (v = v * 2 in for (Integer v : m.values())) changes nothing in the map. The same holds for a lambda: in m.forEach((k, v) -> v = v * 10) the assignment changes only the lambda's own parameter, and the map is unchanged. values() is declared as a plain Collection<V>, which has no replaceAll method (that belongs to List and Map), so m.values().replaceAll(v -> v * 2) does not compile (cannot find symbol). To transform every value, call replaceAll((k, v) -> ...) on the map itself, or setValue on each entry.

TreeMap navigation and range views

A TreeMap keeps its keys sorted (natural order or a Comparator) and implements NavigableMap, so it can answer "nearest key" questions. firstKey()/lastKey() throw NoSuchElementException on an empty map; the navigation methods instead return null when no key qualifies:

MethodReturns
floorKey(k) / floorEntry(k)Greatest key <= k
ceilingKey(k) / ceilingEntry(k)Least key >= k
lowerKey(k) / higherKey(k)Strictly less / strictly greater
headMap(to)Keys < to (exclusive)
tailMap(from)Keys >= from (inclusive)
headMap(to, true), tailMap(from, false), subMap(a, ai, b, bi)Explicit inclusivity
descendingMap()Reverse-ordered view
pollFirstEntry() / pollLastEntry()Removes and returns an end entry (null if empty)
import java.util.*;

public class Main {
    public static void main(String[] args) {
        TreeMap<Integer, String> m = new TreeMap<>();
        m.put(50, "C");
        m.put(70, "B");
        m.put(90, "A");
        System.out.println(m.floorKey(75) + " " + m.ceilingKey(75)
            + " " + m.headMap(70) + " " + m.tailMap(70)
            + " " + m.lowerKey(50));
        NavigableMap<Integer, String> tail = m.tailMap(60, true);
        m.put(80, "B+");
        System.out.println(tail + " " + m.descendingMap());
    }
}

Output (run on JDK 25):

70 90 {50=C} {70=B, 90=A} null
{70=B, 80=B+, 90=A} {90=A, 80=B+, 70=B, 50=C}

Range maps are views, not copies: a key added to the backing map later appears in the view if it falls inside the range, and putting a key outside a view's range through the view throws IllegalArgumentException.

Deque as a stack and as a queue

A Deque (double-ended queue) allows insertion and removal at both ends; ArrayDeque is the usual implementation and LinkedList also implements it. Used as a stack, push, pop and peek all work at the head; used as a queue, offer/add insert at the tail while poll/remove/peek work at the head. In short: push = addFirst, offer = offerLast, pop = removeFirst, poll = pollFirst.

OperationThrows on failureReturns special value on failure
Insert at headaddFirst(e), push(e)offerFirst(e) (returns false if a capacity-bounded deque is full)
Insert at tailaddLast(e), add(e)offerLast(e), offer(e)
Remove headremoveFirst(), remove(), pop()pollFirst(), poll() → null
Remove tailremoveLast()pollLast() → null
Examine headgetFirst(), element()peekFirst(), peek() → null
Examine tailgetLast()peekLast() → null

"Failure" means different things for the two halves of the table. An insert fails only when a capacity-bounded deque is full: addFirst/push/add then throw IllegalStateException while offer… return false. ArrayDeque and LinkedList are unbounded, so their inserts never fail, and an empty deque never makes an insert throw. A remove or examine fails when the deque is empty: the throwing methods throw NoSuchElementException and the others return null. Do not confuse the no-argument remove() (removes the head, throws when empty) with remove(Object o), inherited from Collection, which removes the first equal element and returns false when there is none — it never throws for a missing element.

ArrayDeque rejects null elements with NullPointerException from every insert method, because null is the "empty" signal of poll/peek; LinkedList accepts null. A deque's toString lists elements from head to tail.

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Deque<String> d = new ArrayDeque<>();
        d.offerFirst("m");
        d.add("n");
        d.push("o");
        d.addLast("p");
        System.out.println(d + " " + d.peekFirst() + " "
            + d.peekLast());
        System.out.println(d.pollLast() + " " + d.remove() + " " + d);
        System.out.println(d.remove("zz") + " " + d);
        d.clear();
        System.out.println(d.poll() + " " + d.peek());
        try {
            d.remove();
        } catch (NoSuchElementException e) {
            System.out.println("remove() on empty: NoSuchElement");
        }
    }
}

Output (run on JDK 25):

[o, m, n, p] o p
p o [m, n]
false [m, n]
null null
remove() on empty: NoSuchElement

Sequenced collections: first, last and reversed()

Sequenced collections (Java 21+) are the interfaces SequencedCollection, SequencedSet and SequencedMap, which give every collection with a defined encounter order the same end-access methods. List, Deque, LinkedHashSet, SortedSet/TreeSet, LinkedHashMap and SortedMap/TreeMap all implement them; HashSet and HashMap do not. Because these are interface methods, they are only callable when the variable's declared type is sequenced: Set<String> s = new LinkedHashSet<>(); s.addFirst("x"); does not compile.

  • SequencedCollection: addFirst, addLast, getFirst, getLast, removeFirst, removeLast, reversed(). On an empty collection, get/remove First/Last throw NoSuchElementException (a bad index on a list throws IndexOutOfBoundsException instead).
  • SequencedSet (LinkedHashSet): a plain add of an existing element keeps its position, but addFirst/addLast move an existing element to that end.
  • SequencedMap: putFirst, putLast (moving an existing key in a LinkedHashMap), firstEntry, lastEntry, pollFirstEntry, pollLastEntry, sequencedKeySet(), sequencedValues(), sequencedEntrySet(), reversed(). The entries from firstEntry/lastEntry/poll…Entry are unmodifiable snapshots — setValue throws UnsupportedOperationException.

reversed() is a live view

reversed() returns a reverse-ordered view that reads and writes through to the original: the view's first element is the original's last, so view.addFirst(x) appends to the original and view.removeLast() removes the original's first element. For a sorted set, the reversed view still accepts add and remove, and new elements land in sorted position.

import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(List.of("p", "q", "r"));
        List<String> rev = list.reversed();
        rev.addLast("o");
        rev.removeFirst();
        System.out.println(list + " " + rev + " "
            + list.getFirst() + " " + list.getLast());
        LinkedHashMap<String, Integer> lm = new LinkedHashMap<>();
        lm.put("x", 1);
        lm.put("y", 2);
        lm.putFirst("y", 3);
        System.out.println(lm + " " + lm.firstEntry() + " "
            + lm.reversed());
        try {
            new TreeSet<>(Set.of("b")).addLast("z");
        } catch (UnsupportedOperationException e) {
            System.out.println("TreeSet.addLast: UOE");
        }
    }
}

Output (run on JDK 25):

[o, p, q] [q, p, o] o q
{y=3, x=1} y=3 {x=1, y=3}
TreeSet.addLast: UOE

Where sequenced methods throw

CallResult
A positional insert on a sorted set (TreeSet or any other SortedSet)UnsupportedOperationException — position comes from the ordering
A positional put on a sorted map (TreeMap or any other SortedMap)UnsupportedOperationException
Any mutator on an unmodifiable collection or on a view of one, reversed() includedUnsupportedOperationException — a view of an unmodifiable collection is unmodifiable
addFirst/addLast on a map's sequencedKeySet() viewUnsupportedOperationException — no value to pair with. (On keySet(), declared as a plain Set, addFirst does not even compile; its add throws UnsupportedOperationException.)
removeFirst() on an Arrays.asList listUnsupportedOperationException — fixed size

Tip. Objective 5.1 is examined through short, complete programs that build an array or collection, change it and print it, so expect to state the output, whether the code compiles, or which exception is thrown. Array items probe default values, length versus last index, null rows in ragged arrays, shallow clone of 2D arrays, equals versus Arrays.equals, and binarySearch, compare and mismatch results. List items mix Arrays.asList, List.of, List.copyOf and unmodifiable views, the remove(int)/remove(Object) overloads, the return value of set, and removal inside loops. Set and map items hinge on missing or inconsistent equals/hashCode, comparators that return 0, return values of put, remove, putIfAbsent and getOrDefault, null results from merge and compute, view write-through and factory-map restrictions. Navigation and sequenced items ask for floor/ceiling/higher/lower results, range-view bounds and liveness, which Deque end a method uses and how it behaves when empty, and what reversed(), addFirst and putFirst do on lists, LinkedHashSet, TreeSet, LinkedHashMap and TreeMap — including the calls that throw UnsupportedOperationException.

Key takeaways
  • New array elements default to 0, 0.0, false, '\u0000' or null; the last index is length - 1; int[] g[] is an int[][]; only the first dimension of new int[3][] is required, and its unassigned rows are null.
  • Arrays don't override equals or toString — use Arrays.equals, Arrays.toString and Arrays.compare/mismatch; clone() of a 2D array shares the rows.
  • Arrays.binarySearch needs a sorted array and returns -(insertion point) - 1 for a missing key.
  • Arrays.asList is fixed-size and writes through to its array (set and sort work); List.of/List.copyOf are unmodifiable (sort throws too) and reject null; unmodifiableList and subList are live views.
  • On a List<Integer>, remove(1) removes index 1; set returns the replaced element; remove inside for-each usually throws ConcurrentModificationException — use removeIf or Iterator.remove.
  • thenComparing only breaks ties, and reversed() reverses the whole comparator chain to its left.
  • HashSet/HashMap need consistent equals(Object) and hashCode; TreeSet uses its comparator for add, contains and remove, keeping the first "equal" element; Set.equals compares elements only.
  • put returns the old value; getOrDefault ignores null values but putIfAbsent overwrites them; a null result from merge or compute* removes the mapping.
  • Deque: push/pop/peek work at the head, offer/add at the tail; poll/peek return null on empty, pop/remove()/element throw, remove(Object) just returns false; ArrayDeque rejects null.
  • Sequenced collections add getFirst/getLast/addFirst/addLast/reversed(); reversed() writes through, and sorted sets/maps and unmodifiable views throw UnsupportedOperationException on positional inserts.

Frequently asked questions

What is the difference between Arrays.asList and List.of in Java?

Arrays.asList returns a fixed-size list backed by the array: set works and writes through to the array, but add and remove throw UnsupportedOperationException, and null elements are allowed. List.of returns an unmodifiable list that is independent of any array: set, add and remove all throw UnsupportedOperationException, and null elements — even in contains(null) — throw NullPointerException.

Why does list.remove(1) remove the second element of a List<Integer> instead of the value 1?

List has two remove methods, remove(int index) and remove(Object o). The argument 1 is an int, so the compiler picks remove(int) as an exact match without boxing, and the element at index 1 is removed. To remove the value 1, call remove(Integer.valueOf(1)). If the variable is declared as Collection<Integer>, only remove(Object) exists, so the same call removes the value.

When does removing an element inside a for-each loop throw ConcurrentModificationException?

Removing an element through the list itself (list.remove) while a for-each loop iterates it makes the iterator's next call throw ConcurrentModificationException. If the removed element was the second-to-last one, the size drops so hasNext returns false and the loop ends without an exception, silently skipping the last element. Use removeIf or an Iterator's remove method instead.

How does a TreeSet decide that two elements are duplicates?

A TreeSet uses its Comparator, or the elements' compareTo method, rather than equals. If the comparison returns 0, the new element is treated as a duplicate and add returns false, even when equals would say the two objects differ. Elements must be Comparable or a Comparator must be supplied, otherwise add throws ClassCastException.

What does Arrays.binarySearch return when the key is not found?

It returns -(insertion point) - 1, where the insertion point is the index of the first element greater than the key (or the array length if all elements are smaller). The result is always negative for a missing key. The array must already be sorted in the same order; on an unsorted array the result is undefined.

What happens when a Map.merge or compute function returns null?

For merge, compute, computeIfAbsent and computeIfPresent, a null result from the function removes the existing mapping for that key, or adds nothing if there was none. Any non-null result is stored as the key's new value and returned.

Which Deque methods throw on an empty deque and which return null?

On an empty Deque, pop, remove, removeFirst, removeLast, element, getFirst and getLast throw NoSuchElementException. poll, pollFirst, pollLast, peek, peekFirst and peekLast return null. ArrayDeque does not allow null elements at all, so any insert of null throws NullPointerException. Inserts never fail because a deque is empty; they fail only when a capacity-bounded deque is full, where add/push throw IllegalStateException and offer returns false.

What are sequenced collections in Java?

Sequenced collections are the SequencedCollection, SequencedSet and SequencedMap interfaces added in Java 21 for collections with a defined encounter order, such as List, Deque, LinkedHashSet, TreeSet, LinkedHashMap and TreeMap. They add getFirst, getLast, addFirst, addLast, removeFirst, removeLast (putFirst, putLast, firstEntry and pollFirstEntry for maps) and reversed(), which returns a live reverse-ordered view. Sorted sets and maps throw UnsupportedOperationException from addFirst/addLast and putFirst/putLast.

Source

This lesson covers the "Using Arrays and Collections to Store and Retrieve Data" domain of the official 1Z0-831 exam guide. Vendors revise their guides — check the source for the current version.

Test yourself on this topic
1Z0-831 practice questions, with full explanations.
Practice now

Sign up free to mark lessons complete, bookmark topics and track your exam readiness.

Spotted a mistake in this lesson?