Fundamentals 10 min read

Understanding Java List.remove Overloads and the Pitfalls of Arrays.asList

This article explains the overloaded remove methods in Java's List interface, demonstrates common mistakes when removing elements from ArrayList, clarifies the behavior of Arrays.asList with primitive arrays versus object arrays, and highlights related issues such as unsupported add/remove operations and index‑based deletions.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Understanding Java List.remove Overloads and the Pitfalls of Arrays.asList

Java provides several collection classes, and the List interface defines two overloaded remove methods: remove(Object o) for removing a specific element and remove(int index) for removing by position. Misunderstanding these overloads can lead to subtle bugs.

Consider the following test that removes an element by index:

@Test
public void testStrList() {
    ArrayList
strs = new ArrayList<>();
    
    strs.add("hello");
    strs.add("coding");
    strs.add("word");
    
    strs.remove(1);
    log.info("Arrays  after is [{}] ", Arrays.toString(strs.toArray()));
}

The code removes the element at index 1 , so the resulting list contains [hello, word] . A more confusing scenario arises when the same method name is used with an Integer object:

@Test
public void testList() {
   ArrayList
nums = new ArrayList<>();
   
   for (int i = 0 ; i < 5 ; i++) {
       nums.add(5-i);
   }
   
   // <1> nums.remove(new Integer(3));
   nums.remove(3);
   log.info("Arrays  after is [{}] ", Arrays.toString(nums.toArray()));
}

If nums.remove(3) is executed, it removes the element at index 3 (value 2 ). If the commented line is uncommented and the index‑based call is commented out, nums.remove(new Integer(3)) removes the element whose value is 3 . This illustrates the difference between the two overloads.

The List interface declaration makes this clear:

public interface List
extends Collection
{
    // ...
    boolean remove(Object o);
    // ...
    E remove(int index);
    // ...
}

When removing elements in a loop based on previously collected indices, developers often encounter unexpected results because the list size changes after each removal. The following example demonstrates this issue:

public void testStrList() {
    ArrayList
strs = new ArrayList<>();
    
    strs.add("hello");
    strs.add("coding");
    strs.add("word");
    
    // define matching rule
    ArrayList
mapStrs = new ArrayList<>(Arrays.asList("hello"));
    
    // store matching indices
    ArrayList
index = new ArrayList<>();
    for (int i = 0 ; i < strs.size() ; i++) {
        if (mapStrs.contains(strs.get(i))) {
            index.add(i);
        }
    }
    
    // delete matching info
    for (int i = 0 ; i < index.size() ; i++) {
        strs.remove(index.get(i));
    }
    log.info("strs removed size is [{}] ", strs.size());
}

Because the indices shift after each removal, the final size may not reflect the intended deletions.

Another frequent source of confusion is Arrays.asList . When a primitive array is passed, the method treats the whole array as a single element, producing a list of size 1 :

int[] arr = {1, 2, 3};
List listArray = Arrays.asList(arr);

In contrast, passing individual values creates a list with three elements:

List list = Arrays.asList(1, 2, 3);

The implementation of asList uses a generic var‑args parameter:

public static List asList(T... a) {
    return new ArrayList<>(a);
}

When a primitive int[] is supplied, it becomes a single object of type int[] , not an Integer[] . Using an object array avoids the problem:

Integer[] arr2 = {1, 2, 3};
List list = Arrays.asList(arr2);

Lists returned by Arrays.asList are fixed‑size. Attempting to add or remove elements triggers an UnsupportedOperationException because the underlying class does not override the mutable methods of AbstractList :

Integer[] arr2 = {1, 2, 3};
List list = Arrays.asList(arr2);
list.add(3, 4);

The relevant method in AbstractList is:

public void add(int index, E element) {
    throw new UnsupportedOperationException();
}

In summary, developers should be aware of the two remove overloads in List , the pitfalls of using Arrays.asList with primitive arrays, and the immutable nature of the list it returns. Understanding these details helps avoid subtle bugs in everyday Java development.

JavaCollectionsArrays.asListlistArrayListremove
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.