Tuesday, 11 August 2015

How to remove elements from an ArrayList

To remove elements from an ArrayList we can use remove method provided by ArrayList or the remove method provided by Iterator. In this post we'll see when to use which method and why.

ArrayList remove method

ArrayList provides two overloaded remove methods -
  • remove(int index) - This method takes int (which specifies the index in the list) as parameter and removes the element at the specified position in this list. Shifts any subsequent elements to the left (subtracts one from their indices).
  • public boolean remove(Object o) - This method takes the object, which has to be removed as parameter and removes the first occurrence of the specified element from this list, if it is present. If the list does not contain the element, it is unchanged.

If you are just removing an element from an ArrayList without looping the list then you can remove an element by giving its index in the list or specifying the object itself.

As example - If there is a list myList and you want to remove the element at index 4 then it can be done this way -

myList.remove(4);

Or by giving object to remove that object

myList.remove(obj);

Removing element while iterating the list

Note that using ArrayList's remove method with enhanced for loop or iterator may result in ConcurrentModificationException.

ArrayList's remove method can be used with normal for loop but it may give undesired result because of the fact that all the other elements are shifted to the left when an element is removed.
As exp. In the given program code if I want to remove the elements at index 3 & 4 then ideally Hyderabad and Bangalore should be removed from the list. Let's see what happens -

public class RemoveFromListDemo {

    public static void main(String[] args) {
        List<String> cityList = new ArrayList<String>();
        cityList.add("Delhi");
        cityList.add("Mumbai");
        cityList.add("Kolkata");
        cityList.add("Hyderabad");
        cityList.add("Bangalore");
        cityList.add("Mumbai");
        
        for(int i = 0; i < cityList.size(); i++){
            if(i == 3 || i == 4){
                cityList.remove(i);
            }
        }
        
        System.out.println("After deletion " );
        for(String city : cityList){
            System.out.println("city " + city);
        }
    }
}

Output

After deletion 
city Delhi
city Mumbai
city Kolkata
city Bangalore

It can be seen that Hyderabad is removed alright but Mumbai is removed instead of Bangalore. This happened because after Hyderabad is removed elements in the list are shifted and Bangalore came in the place of Hyderabad and Mumbai in place of Bangalore. Thus Mumbai was at index 4 hence removed.

In the previous code if we were using city(object) in the if condition then it would have run fine.

public class RemoveFromListDemo {

    public static void main(String[] args) {
        List<String> cityList = new ArrayList<String>();
        cityList.add("Delhi");
        cityList.add("Mumbai");
        cityList.add("Kolkata");
        cityList.add("Hyderabad");
        cityList.add("Bangalore");
        cityList.add("Mumbai");
        
        for(int i = 0; i < cityList.size(); i++){
            String city = cityList.get(i);
            if(city.equalsIgnoreCase("Kolkata") || city.equalsIgnoreCase("Bangalore")){
                cityList.remove(i);
            }
        }
        
        System.out.println("After deletion " );
        for(String city : cityList){
            System.out.println("city " + city);
        }
    }
}

Output

After deletion 
city Delhi
city Mumbai
city Hyderabad
city Mumbai

Note here in place of cityList.remove(i); we can also use cityList.remove(city);

RemoveIf

If you are using Java 8 then removeIf method can be used, which takes Predicate functional interface as a parameter. In that case we can write the removal code with in one line as -

for(int i = 0; i < cityList.size(); i++){
    cityList.removeIf(p -> p.equalsIgnoreCase("Hyderabad") || 
        p.equalsIgnoreCase("Bangalore"));
}

Concurrent Modification Exception

If we use the ArrayList remove method while iterating using enhanced for loop or iterator it will throw Concurrent Modification Exception as the iterators returned by ArrayList class's iterator and ListIterator methods are fail-fast. Which means if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. (A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification.)
public class RemoveFromListDemo {

    public static void main(String[] args) {
        List<String> cityList = new ArrayList<String>();
        cityList.add("Delhi");
        cityList.add("Mumbai");
        cityList.add("Kolkata");
        cityList.add("Hyderabad");
        cityList.add("Bangalore");
        cityList.add("Mumbai");
        
                
        //System.out.println("After deletion " );
        for(String city : cityList){
            if(city.equalsIgnoreCase("Kolkata"))
                cityList.remove(city);
            //System.out.println("city " + city);
        }
    }
}

Output

Exception in thread "main" java.util.ConcurrentModificationException
 at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
 at java.util.ArrayList$Itr.next(Unknown Source)
 at org.netjs.prog.RemoveFromListDemo.main(RemoveFromListDemo.java:20)

As it can be seen here ConcurrentModificationException is thrown because we are trying to structurally modify the list which it is iterated. If you want to remove an element from a list while iterating it safe option is to use Iterator class remove() method. Example code for that is given later.

ArrayList remove method and AutoBoxing problem

While removing elements from an ArrayList of Integers we may get problem because of Autoboxing. As alreay mentioned there are two overloaded remove methods -

  • Remove(int index)
  • Remove(Object o)

If we give an int as parameter then it will always be treated as a call to remove method with int parameter.
Let's clear it with an example

public class RemoveFromListDemo {
    public static void main(String[] args) {
        
        List<Integer> numberList = new ArrayList<Integer>();
        // adding to list as int, no need to do
        // new Integer(1)
        numberList.add(1);
        numberList.add(2);
        numberList.add(3);
        numberList.add(4);
        
        // Removing by index 1
        numberList.remove(1);
        // This time removing the integer Object 4
        numberList.remove(4);
    }
}

Output

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 4, Size: 3
 at java.util.ArrayList.rangeCheck(Unknown Source)
 at java.util.ArrayList.remove(Unknown Source)
 at org.netjs.prog.RemoveFromListDemo.main(RemoveFromListDemo.java:20)

So, even if a user thinks while removing the second time that he is giving an object as parameter and hoping autoboxing will take care of all the wrapping to Integer Object chore it won't happen in this case. Second call will also be treated as a call to remove method with int parameter. First remove has already removed one element so now the list size is 3 and trying to access index 4 in such a list will throw IndexOutOfBoundsException.

So in this case user has to explicitly tell the compiler that remove method which takes object as parameter has to be called.

numberList.remove(new Integer(4)); 

Iterator remove method

While looping if we want to remove any element we have to use Iterator's remove method so that we don't get Concurrent Modification Exception.

public class RemoveFromListDemo {

    public static void main(String[] args) {
        List<String> cityList = new ArrayList<String>();
        cityList.add("Delhi");
        cityList.add("Mumbai");
        cityList.add("Kolkata");
        cityList.add("Hyderabad");
        cityList.add("Bangalore");
        cityList.add("Mumbai");
        
                
        Iterator<String> itr = cityList.iterator();
        int i = 0;
        while(itr.hasNext()){
            System.out.println("city " + itr.next());
            if(i == 3 || i == 4){
                itr.remove();
            }
            i++;
        }
        
        System.out.println("After deletion " );
        for(String city : cityList){
            System.out.println("city " + city);
        }
    }
}

Output

city Delhi
city Mumbai
city Kolkata
city Hyderabad
city Bangalore
city Mumbai
After deletion 
city Delhi
city Mumbai
city Kolkata
city Mumbai

That's all for this topic How to remove elements from an ArrayList in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. ArrayList in Java
  2. How ArrayList works internally in Java
  3. How to remove duplicate elements from an ArrayList in Java
  4. How to sort arraylist in Java
  5. How to join lists in Java
  6. How HashMap internally works in Java
  7. Java Collections interview questions

You may also like -

No comments:

Post a Comment