set()

Replaces the element at an index and returns the old one, without changing the size of the list.

Signature
E set(int index, E element)
  • Added in Java Java 1.2

Parameters

ParameterTypeDescription
$indexintZero-based position of the element to replace, from 0 to size() - 1.
$elementEThe new value to store at that position.

Return value

EThe element that was previously at the index.

Errors

UnsupportedOperationException if the list is unmodifiable. IndexOutOfBoundsException if index < 0 or index >= size(). NullPointerException if the list rejects nulls. ClassCastException or IllegalArgumentException if the element cannot be stored.

set(index, element) overwrites one slot. The list keeps the same size, every other element stays where it was, and the method returns whatever was there before. It is the write counterpart of get and costs the same: constant time on ArrayList, linear on LinkedList.

set is not add

set only replaces. It cannot extend the list, so set(size(), x) throws IndexOutOfBoundsException. This trips people who create new ArrayList<>(10) and then call set(0, x): the number is the initial capacity of the backing array, not the size. The list is still empty. If you need a list of ten placeholders, use new ArrayList<>(Collections.nCopies(10, null)) or similar.

Which lists allow it

  • ArrayList and LinkedList: yes.
  • Arrays.asList: yes, and the change writes through to the underlying array. It is fixed-size, not read-only.
  • List.of, List.copyOf, Stream.toList(), Collections.unmodifiableList: no, they throw UnsupportedOperationException.
  • A subList or reversed() view of a modifiable list: yes, and the change lands in the original list.

Updating records in a list

Records are immutable, so to change one entry in an in-memory store you build a new record and set it at the same index. Find the index with a loop or indexOf; for frequent updates by id, a Map is the better structure.

To change every element, replaceAll(operator) (Java 8) is clearer than an indexed loop, for example trimming and lower-casing a list of tags. A ListIterator also has a set method that replaces the element just returned by next(), which is useful when the replacement depends on a condition.

The returned old value is handy for audit logs and change events: you get the before and after in one call.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Replacing an updated entity in an in-memory repository during a PUT request.
  • Normalising user-supplied tags or email addresses in place before saving them.
  • Recording the old and new value of a changed slot for an audit trail.

Frequently asked questions

What is the difference between set and add on a Java list?

set replaces the element at an existing index and keeps the size the same; add inserts a new element and grows the list. set never extends a list, so set(size(), x) throws.

Why does set throw IndexOutOfBoundsException on a new ArrayList with a capacity?

The constructor argument is the initial capacity of the internal array, not the number of elements. The list is still empty, so every index is out of bounds until you add elements.

More examples

Updating a record in an in-memory store

Records cannot be changed in place, so the update stores a new record at the same index. The returned old record feeds the audit line.

Example · java
record User(int id, String name) {}

void main() {
    List<User> users = new ArrayList<>(List.of(new User(1, "Ada"), new User(2, "Linus")));

    for (int i = 0; i < users.size(); i++) {
        if (users.get(i).id() == 2) {
            User before = users.set(i, new User(2, "Grace"));
            IO.println("audit: " + before.name() + " -> Grace");
        }
    }
    IO.println(users);
}
// Output:
// audit: Linus -> Grace
// [User[id=1, name=Ada], User[id=2, name=Grace]]

Capacity is not size

The constructor argument only sizes the internal array. Filling the list with placeholders first gives set real slots to replace.

Example · java
void main() {
    List<String> slots = new ArrayList<>(3);
    try {
        slots.set(0, "x");
    } catch (IndexOutOfBoundsException e) {
        IO.println(e.getMessage());
    }

    List<String> filled = new ArrayList<>(Collections.nCopies(3, "-"));
    filled.set(0, "x");
    IO.println(filled);
}
// Output:
// Index 0 out of bounds for length 0
// [x, -, -]

replaceAll and ListIterator.set

replaceAll applies one function to every slot. ListIterator.set replaces only the element just returned by next, which suits conditional edits.

Example · java
void main() {
    List<String> tags = new ArrayList<>(List.of(" Java ", "SQL", " http"));
    tags.replaceAll(t -> t.strip().toLowerCase());
    IO.println(tags);

    ListIterator<String> it = tags.listIterator();
    while (it.hasNext()) {
        if (it.next().equals("sql")) {
            it.set("postgres");
        }
    }
    IO.println(tags);
}
// Output:
// [java, sql, http]
// [java, postgres, http]

Discussion

  • Be the first to comment on this lesson.