set()
Replaces the element at an index and returns the old one, without changing the size of the list.
E set(int index, E element)- Added in Java Java 1.2
Parameters
| Parameter | Type | Description |
|---|---|---|
$index | int | Zero-based position of the element to replace, from 0 to size() - 1. |
$element | E | The 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
ArrayListandLinkedList: 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 throwUnsupportedOperationException.- A
subListorreversed()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
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.
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.
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.
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