skip to content

What does reversed() return, and how does it behave with respect to the underlying collection?

level: seniorimportance: should knowfreq 40%

answer

  1. View, not a copy — O(1) to obtain
  2. r.getFirst() == c.getLast()
  3. Writes invert and propagate to the source
  4. Fail-fast: CME on structural change during iteration
  5. Copy (new ArrayList<>) for an independent snapshot

basics

~20 s

reversed() returns a view of the same collection in opposite order, not a copy. It is backed by the original, so reads reflect later changes, and supported writes on the view (like addFirst) modify the original.

solid answer

~50 s

`reversed()` returns a **live view** over the same backing collection with the encounter order flipped — it does not copy elements. Iterating the view yields elements last-to-first, and `getFirst()` on the view equals `getLast()` on the original. Because it is a view, structural changes to the underlying collection are visible through it, and mutating operations on the view that are supported (e.g. `addFirst` on the reversed view maps to `addLast` on the original) write through to the backing collection. This makes it cheap (O(1) to obtain) and memory-light, but it carries the usual view hazards: it can throw `ConcurrentModificationException` if the backing collection is structurally modified during iteration through another path, and modifications through one handle are seen by the other. If you need a stable, independent snapshot, copy it explicitly (e.g. `new ArrayList<>(c.reversed())`). For `SortedSet`/`SortedMap`, `reversed()` is effectively the reverse-comparator ordering, similar to `descendingSet()`/`descendingMap()`.

go deeper

for a junior

Knows reversed() gives the elements in opposite order and can iterate it.

for a middle

States it returns a view rather than a copy and that getFirst on the view equals getLast on the source.

for a senior

Explains write-through inversion, fail-fast iteration risk, inherited unmodifiable restrictions, and how to take an independent snapshot.

for a principal

Compares with descendingSet/descendingMap, reasons about complexity preservation, aliasing/concurrency hazards, and API design implications of returning live views.

## What a "view" means A **view** is a lightweight object that *delegates* to another collection rather than owning its own elements. `Collections.unmodifiableList`, `List.subList`, `Map.keySet`, and `TreeMap.descendingMap` are all views. The defining property: the view and the source share the **same underlying data**, so changes made through either are seen through the other (subject to what each permits). `SequencedCollection.reversed()` (and `SequencedMap.reversed()`) returns such a view, presenting the same elements in **reverse encounter order**. Crucially it is **not a copy** — getting it is O(1) and uses negligible extra memory. ## Behavioral mapping For a sequenced collection `c` and `r = c.reversed()`: - `r.getFirst()` == `c.getLast()`, and `r.getLast()` == `c.getFirst()`. - Iterating `r` walks `c` from back to front. - Supported mutations invert: `r.addFirst(x)` is `c.addLast(x)`; `r.addLast(x)` is `c.addFirst(x)`; `r.removeFirst()` is `c.removeLast()`. - `r.reversed()` returns a view equivalent to `c` again (reversing twice). ## Consequences of being a view 1. **Reflects live changes.** If you add to `c` after creating `r`, the new element appears in `r` (at the appropriate end). There is no stale snapshot. 2. **Writes propagate both ways.** A supported write through `r` changes `c`, and vice versa. 3. **Fail-fast iteration.** If `c` is structurally modified (size changes) while you iterate `r` — except through the iterator's own remove — you can get a `ConcurrentModificationException`, exactly as with normal collection iteration. 4. **Inherited restrictions.** If `c` is unmodifiable or fixed-size (e.g. `List.of(...)`), the corresponding mutating ops on `r` also throw `UnsupportedOperationException`. ## When to copy instead If you need the reversed order as an **independent, stable** structure — to hand off, to mutate without touching the original, or to iterate safely while the source changes — materialize it: `var snapshot = new ArrayList<>(c.reversed());`. That is O(n) and decoupled from `c`. ## Relationship to pre-existing reverse views For sorted types, `reversed()` overlaps conceptually with `NavigableSet.descendingSet()` / `NavigableMap.descendingMap()`, which were already views in the reverse comparator order. `reversed()` generalizes the *view-based reverse* idea to every sequenced type (including `ArrayList`, which never had a built-in reverse view before). ## Performance note Obtaining the view is constant time. Operations on the view have the **same complexity as on the source** (a reversed `ArrayList` view still indexes in O(1); a reversed `LinkedList` view still traverses). Reversal does not change algorithmic cost; it only relabels the ends.

  • How do you get an independent reversed copy rather than a view?
    Wrap it: new ArrayList<>(c.reversed()) (or stream/collect). That materializes the elements so later changes to c don't affect it and you can mutate it freely.
  • What is the time cost of calling reversed()?
    O(1) — it returns a view object; no elements are touched. Operations on the view keep the source's per-operation complexity.

saying these in an interview costs you the question

  • Believing reversed() allocates a reversed copy of all elements
  • Assuming you can safely mutate the source while iterating the view
  • Thinking the view is read-only — supported writes do write through (mapped to the opposite end)
  • Confusing reversed() with sorting in descending order for a non-sorted collection

context