ArrayList Replace at Index in Java: set() and replaceAll()

Replace an element in a Java ArrayList with set(index, element), which returns the old element. Find the index by value with indexOf(), replace all matches with Collections.replaceAll() or List.replaceAll(), and avoid IndexOutOfBoundsException.

ArrayList

The method set(index, newElement) replaces the element at a given index of an ArrayList and returns the element that was there before. When we know the old value but not its position, we find the index with indexOf() first. The list keeps its size, because set() only overwrites one slot.

We replace elements whenever one item of a list changes but the rest stays as it is, such as a renamed task in a to-do app or a corrected price in a shopping cart.

The following example replaces elements in a to-do list by index or by value, and replaces several elements at once, with the result of each line as a comment.

List<String> tasks = new ArrayList<>(List.of("email", "gym", "lunch", "call"));

String old = tasks.set(1, "yoga");                                  // gym, tasks = [email, yoga, lunch, call]
int index = tasks.indexOf("lunch");                                 // 2
String replaced = tasks.set(index, "dinner");                       // lunch, tasks = [email, yoga, dinner, call]
boolean changed = Collections.replaceAll(tasks, "call", "meeting"); // true, tasks = [email, yoga, dinner, meeting]
tasks.replaceAll(String::toUpperCase);                              // [EMAIL, YOGA, DINNER, MEETING]

String bad = tasks.set(9, "gym");                                   // IndexOutOfBoundsException: Index 9 out of bounds for length 4

Notice that each set() call returns the old element, so we can log or undo the change. An index outside the list throws an IndexOutOfBoundsException instead of adding a new element.

Next, we look at how set() works and how it differs from add(). After that, we replace elements by value without the exception and replace many elements at once. The last sections cover lists of objects and lists that do not allow changes.

1. Replacing an Existing Item

To replace an existing item, we must find the item’s exact position (index) in the ArrayList. Once we have the index, we can use the set() method to replace the old element with a new item.

  • Find the index of an existing item using the indexOf() method.
  • Use set(index, object) to update the list with the new item.

The method set() is declared in the List interface, so it works the same way on every modifiable list. The index starts at 0, and a valid index goes from 0 to size() – 1. For an ArrayList, set() runs in constant time, because the list stores its elements in an array and writes the new element straight into one array slot.

Note that the IndexOutOfBoundsException will occur if the provided index is out of bounds. The exception message names the bad index and the list length, which helps when the index comes from a calculation.

List<String> tasks = new ArrayList<>(List.of("email", "gym", "lunch", "call"));

String tooBig = tasks.set(9, "yoga");              // IndexOutOfBoundsException: Index 9 out of bounds for length 4
String atSize = tasks.set(tasks.size(), "yoga");   // IndexOutOfBoundsException: Index 4 out of bounds for length 4
String negative = tasks.set(-1, "yoga");           // IndexOutOfBoundsException: Index -1 out of bounds for length 4

1.1. set() vs add(index, element)

Both methods take an index and an element, but they do different things. The method set() overwrites the element at the index, so the size stays the same. The method add(index, element) inserts the element at the index and shifts the element at that position, and every element after it, one place to the right, so the size grows by one.

List<String> tasks = new ArrayList<>(List.of("email", "gym", "lunch"));
String old = tasks.set(1, "yoga");      // gym, tasks = [email, yoga, lunch], size 3
tasks.add(1, "coffee");                 // tasks = [email, coffee, yoga, lunch], size 4
Two rows of list boxes. Top row: set(1, "yoga") on [email, gym, lunch] overwrites gym at index 1, giving [email, yoga, lunch] with size 3 and returning gym. Bottom row: add(1, "coffee") on [email, yoga, lunch] inserts coffee at index 1 and shifts yoga and lunch one place right, giving [email, coffee, yoga, lunch] with size 4.
The method set() overwrites one slot and keeps the size, whereas add(index, element) shifts the following elements and grows the list.

The method set() never adds an element, so set(size(), element) throws an exception instead of appending. To append, we call add(element).

2. Replacing an Element by Value

Our to-do list contains four tasks, and we update the value “lunch” with “dinner”. First, indexOf() finds the position of the first element that is equal to “lunch”, and set() replaces it.

List<String> tasks = new ArrayList<>(List.of("email", "gym", "lunch", "call"));
int index = tasks.indexOf("lunch");             // 2
String old = tasks.set(index, "dinner");        // lunch, tasks = [email, gym, dinner, call]

We can make the whole replacing process in a single statement, but only when we are sure that the element is in the list. The method indexOf() returns -1 for a missing element, and set(-1, …) throws an exception.

String oldCall = tasks.set(tasks.indexOf("call"), "meeting");   // call, tasks = [email, gym, dinner, meeting]
String fails = tasks.set(tasks.indexOf("swim"), "yoga");        // IndexOutOfBoundsException: Index -1 out of bounds for length 4

For example, a to-do app gets a rename request for a task that another user has deleted a second earlier. The single statement throws an exception for that request, so the safe version checks the index first and reports whether the replacement happened.

static boolean replaceFirst(List<String> list, String oldValue, String newValue) {
  int index = list.indexOf(oldValue);
  if (index < 0) {
    return false;
  }
  list.set(index, newValue);
  return true;
}
boolean renamed = replaceFirst(tasks, "gym", "yoga");    // true, tasks = [email, yoga, dinner, meeting]
boolean missing = replaceFirst(tasks, "swim", "yoga");   // false, tasks unchanged

The method indexOf() compares elements with equals() and also finds a null element, so the helper replaces null values too. To replace the last match instead of the first, we call lastIndexOf().

3. Replacing All Matching Elements

The method indexOf() finds only the first match. When a value occurs more than once, Collections.replaceAll(list, oldValue, newValue) replaces every element that equals oldValue. It returns true when it replaced at least one element, or false when the list had no match.

List<String> week = new ArrayList<>(List.of("gym", "email", "gym"));
boolean changed = Collections.replaceAll(week, "gym", "yoga");    // true, week = [yoga, email, yoga]
boolean none = Collections.replaceAll(week, "swim", "run");       // false

When the new value depends on the old one, we call List.replaceAll() (Java 8) with a function. The function gets each element and returns its replacement, and returning the same element keeps it unchanged.

List<String> week = new ArrayList<>(List.of("gym", "email", "gym"));
week.replaceAll(String::toUpperCase);                         // [GYM, EMAIL, GYM]
week.replaceAll(t -> t.equals("GYM") ? "YOGA" : t);           // [YOGA, EMAIL, YOGA]

Both methods change the list in place. A Stream with map() puts the replaced values into a new list and leaves the original list as it was, which is the better choice when other code still uses the original list.

4. Replacing an Object in a List by Its Id

In real apps, a list holds objects, and we find the element by a field such as an id. For example, a to-do app keeps Task objects, and the user edits the title of the task with id 2. A Java record has no setters, so we replace the whole object with set().

record Task(int id, String title) {}

List<Task> tasks = new ArrayList<>(List.of(new Task(1, "email"), new Task(2, "gym")));

int index = IntStream.range(0, tasks.size())
    .filter(i -> tasks.get(i).id() == 2)
    .findFirst()
    .orElse(-1);                                // 1
if (index >= 0) {
  tasks.set(index, new Task(2, "yoga"));        // [Task[id=1, title=email], Task[id=2, title=yoga]]
}

The IntStream goes over the indexes instead of the elements, so the result is the position that set() needs. The check index >= 0 covers the case where no task has the id.

When we loop over the list anyway, a ListIterator replaces the current element with its own set() method, without an index.

ListIterator<String> it = week.listIterator();
while (it.hasNext()) {
  if (it.next().equals("EMAIL")) {
    it.set("CALLS");                            // week = [YOGA, CALLS, YOGA]
  }
}

5. Replacing in Lists That Do Not Allow Changes

The method set() works on an ArrayList and on the fixed-size list from Arrays.asList(). Lists from List.of() or Collections.unmodifiableList() are unmodifiable, so set() throws an UnsupportedOperationException.

List<String> fixed = Arrays.asList("email", "gym");
String old = fixed.set(1, "yoga");                  // gym, fixed = [email, yoga]

List<String> constant = List.of("email", "gym");
String failed = constant.set(1, "yoga");            // UnsupportedOperationException

List<String> copy = new ArrayList<>(constant);
String fixedCopy = copy.set(1, "yoga");             // gym, copy = [email, yoga]

To change an unmodifiable list, we copy it into a new ArrayList and replace the element in the copy, as the last two lines show. When we create the list ourselves, new ArrayList<>(List.of(…)) gives a list initialized in one line that accepts set() from the start.

6. ArrayList Replace FAQs

6.1. Does set() Change the Size of the List?

No. The method set() overwrites one existing element, so the size stays the same. Methods such as add() and remove() change the size, as we saw in section 1.1.

6.2. Can We Call set() Inside a for-each Loop?

Yes. Setting an element is not a structural modification of the ArrayList, so the loop does not throw a ConcurrentModificationException. Calling add() or remove() in the same loop throws the exception.

List<String> tasks = new ArrayList<>(List.of("email", "gym"));
for (String task : tasks) {
  if (task.equals("gym")) {
    tasks.set(tasks.indexOf(task), "yoga");     // no exception, tasks = [email, yoga]
  }
}

6.3. How Do We Replace an Element in a Plain Array?

We assign the new value to the index, as in names[1] = “yoga”;. An array has a fixed length, so an index outside the array throws an ArrayIndexOutOfBoundsException, which is a subclass of IndexOutOfBoundsException.

6.4. Is set() Thread-Safe?

No. An ArrayList is not synchronized, and when one thread adds or removes elements while another thread calls set(), the Javadoc requires external synchronization. For a list shared between threads, we use Collections.synchronizedList() or a CopyOnWriteArrayList.

7. Conclusion

The method set(index, element) replaces the element at a position and returns the old element, and the list keeps its size. To replace by value, we find the position with indexOf() and check for -1 before we call set().

For many elements at once, Collections.replaceAll() replaces every equal element, and List.replaceAll() applies a function to each element. Lists from List.of() reject every set() call, so we replace the element in an ArrayList copy.

8. References

Happy Learning !!

Source Code on Github

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.