remove()
Removes by index or by value, and avoids the Integer overload trap and the exception from removing inside a loop.
E remove(int index)
boolean remove(Object o)- Added in Java Java 1.2
Parameters
| Parameter | Type | Description |
|---|---|---|
$index | int | For remove(int): zero-based position of the element to remove, from 0 to size() - 1. |
$o | Object | For remove(Object): the value to remove. Only the first element equal to it, by equals, is removed. |
Return value
E or booleanremove(int) returns the element that was removed. remove(Object) returns true if a matching element was found and removed.
Errors
UnsupportedOperationException if the list is unmodifiable or fixed-size. IndexOutOfBoundsException from remove(int) if index < 0 or index >= size(). remove(Object) may throw ClassCastException or NullPointerException if the list does not accept that type or null.
Changelog
- PHP Java 21List gained removeFirst() and removeLast() from SequencedCollection; they throw NoSuchElementException on an empty list.
List has two remove methods. remove(int index) takes out the element at a position and returns it. remove(Object o) finds the first element equal to o, removes it and returns whether it found one. Either way, the elements after it shift left, so on an ArrayList removing near the front is linear time.
The Integer trap
With a List<Integer>, list.remove(1) calls the int overload, because the compiler prefers a match without boxing. It removes the element at index 1, not the value 1. To remove by value, pass an object: list.remove(Integer.valueOf(1)). This bug is common with lists of ids and is silent: the call succeeds, just on the wrong element, or throws IndexOutOfBoundsException if the id is larger than the list.
Removing while looping
Calling list.remove inside a for-each loop over the same list usually throws ConcurrentModificationException on the next step. The iterator checks a modification counter and fails fast. Three safe options:
removeIf(predicate)(Java 8): one call, linear time onArrayList, and the clearest code.- An explicit
Iteratorand its ownremove()method. - Build a filtered copy with a stream and replace the old list.
More than one match
remove(Object) stops after the first match. To drop every occurrence use removeIf(x -> x.equals(value)) or removeAll(List.of(value)). To clear a range, subList(from, to).clear() does it in one shift.
Since Java 21, removeFirst() and removeLast() remove from either end and throw NoSuchElementException if the list is empty. For work queues that remove from the front repeatedly, an ArrayDeque is a better fit than an ArrayList.
Matching uses equals, so removing a record works by value. Removing an instance of a class without equals only works if you pass the very same object.
Example
When to use it
- Evicting expired sessions or tokens from an in-memory cache with removeIf.
- Deleting an entity by id from an in-memory repository during a DELETE request.
- Removing a revoked role from a user's role list before saving it.
Frequently asked questions
How do I remove an Integer value from a List<Integer> instead of an index?
Box the value so the Object overload is chosen: list.remove(Integer.valueOf(5)). A plain list.remove(5) removes the element at index 5.
How do I remove elements from a list while iterating in Java?
Use list.removeIf(condition), or an explicit Iterator and call it.remove(). Calling list.remove inside a for-each loop throws ConcurrentModificationException.
Does remove(Object) remove all matching elements?
No, only the first one. Use removeIf or removeAll to remove every occurrence.
More examples
Dropping expired sessions with removeIf
removeIf removes every match in one pass and reports whether anything changed. A fixed clock value keeps the result predictable.
record Session(String id, long expiresAt) {}
void main() {
long now = 1_000;
List<Session> sessions = new ArrayList<>(List.of(
new Session("s1", 900),
new Session("s2", 1_500),
new Session("s3", 950)));
boolean changed = sessions.removeIf(s -> s.expiresAt() <= now);
IO.println(changed + " " + sessions);
}
// Output:
// true [Session[id=s2, expiresAt=1500]]Removing inside a for-each loop
The for-each loop's hidden iterator detects the change and throws. Iterator.remove is the supported way to remove during iteration.
void main() {
List<String> users = new ArrayList<>(List.of("banned", "ada", "linus"));
try {
for (String u : users) {
if (u.equals("banned")) {
users.remove(u);
}
}
} catch (ConcurrentModificationException e) {
IO.println("ConcurrentModificationException");
}
List<String> fresh = new ArrayList<>(List.of("ada", "banned", "grace", "linus"));
Iterator<String> it = fresh.iterator();
while (it.hasNext()) {
if (it.next().equals("banned")) {
it.remove();
}
}
IO.println(fresh);
}
// Output:
// ConcurrentModificationException
// [ada, grace, linus]First match versus every match
remove(Object) stops at the first equal element. removeAll removes every element contained in the argument collection.
void main() {
List<String> tags = new ArrayList<>(List.of("a", "b", "a", "c", "a"));
tags.remove("a");
IO.println(tags);
tags.removeAll(List.of("a"));
IO.println(tags);
}
// Output:
// [b, a, c, a]
// [b, c]
Discussion