CodeGym/Java Blog/Java Collections/Deleting an element from an ArrayList
Author
Volodymyr Portianko
Java Engineer at Playtika

Deleting an element from an ArrayList

Published in the Java Collections group
members
Hi! In the last lesson, we got acquainted with the ArrayList class, and learned how to perform the most common operations with this class. In addition, we pointed out several differences between an ArrayList and an ordinary array. But we skirted one topic, namely, how to delete elements from an ArrayList. We'll discuss that now. Deleting an element from an ArrayList - 1We've already mentioned that deleting elements from an ordinary array is not very convenient. Since we can't delete the element itself, we can only "zero out" (set to null) its value:
public class Cat {

   private String name;

   public Cat(String name) {
       this.name = name;
   }

   public static void main(String[] args) {

       Cat[] cats = new Cat[3];
       cats[0] = new Cat("Thomas");
       cats[1] = new Cat("Behemoth");
       cats[2] = new Cat("Lionel Messi");

       cats[1] = null;

       System.out.println(Arrays.toString(cats));
   }


@Override
   public String toString() {
       return "Cat{" +
               "name='" + name + '\'' +
               '}';
   }
}
Output: [Cat{name='Thomas'}, null, Cat{name='Lionel Messi'}] But setting an array element to null leaves a "hole". We haven't removed the position in the array, only its contents. Imagine what would happen if we had an array of 50 cats and removed 17 of them this way. We'll have an array with 17 holes. Just try keeping track of them! It's unrealistic to expect to remember the number of empty cells where you can write new values. If you make one mistake, you'll overwrite an object reference that you want. There is, of course, a way to do this a little more carefully: after removing an element, move the elements to the front of the array to put the "hole" at the end:
public static void main(String[] args) {

   Cat[] cats = new Cat[4];
   cats[0] = new Cat("Thomas");
   cats[1] = new Cat("Behemoth");
   cats[2] = new Cat("Lionel Messi");
   cats[2] = new Cat("Fluffy");

   cats[1] = null;

   for (int i = 2; i < cats.length-1; i++) {
       cats [i-1] = cats [i];// Move the elements to the front of the array, so the empty position is at the end
   }

   System.out.println(Arrays.toString(cats));
}
Output: [Cat{name='Thomas'}, Cat{name='Fluffy'}, Cat{name='Fluffy'}, null] This seems better, but it can hardly be called a robust solution. If for no other reason than the fact that we have to write this code every time when we delete an element from an array! This is a bad option. We could go another way and create a separate method:
public void deleteCat(Cat[] cats, int indexToDelete) {
   //...delete the cat corresponding to the index and move the elements
}
But this is also of little use: this method can only work with Cat objects, but not other types. In other words, if a program has another 100 classes that we want to use with arrays, we'll have to write the same method with exactly the same logic in each of them. This is a total disaster -_- But the ArrayList class solves this problem! It implements a special method for removing elements: remove()
public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);
   System.out.println(cats.toString());

   cats.remove(1);

   System.out.println(cats.toString());
}
We pass our object's index to the method, which deletes it (just like in an array). The remove() method has two special features. First, it does not leave "holes". It already implements the logic needed to shift elements when an element is removed from the middle, which we previously wrote ourselves. Look at the output from the previous code:
[Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}]

[Cat{name='Thomas'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}]
We removed one cat from the middle, and the rest were moved so that there were no empty spaces. Second, it can delete objects not only by index (like a normal array), but also by reference:
public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);
   System.out.println(cats.toString());

   cats.remove(lionel);

   System.out.println(cats.toString());
}
Output: [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}] [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Fluffy'}] This can be very convenient if you don't want to always keep track of the desired object's index. It seems we've figured out ordinary deletion. Now let's imagine this situation: we want to iterate over our list and remove a cat with a specific name. To do this, we'll use a fast for loop (also called a for-each loop), which we were introduced to in Rishi's lessons:
public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);

   for (Cat cat: cats) {

       if (cat.name.equals("Behemoth")) {
           cats.remove(cat);
       }
   }

   System.out.println(cats);
}
The code looks perfectly logical. But the result might be a big surprise: Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) at java.util.ArrayList$Itr.next(ArrayList.java:831) at Cat.main(Cat.java:25) There's some sort of an error, and it's unclear why it occurred. This process involves a number of nuances that must be addressed. Here's the general rule you need to remember: You cannot simultaneously iterate over a collection and change its elements. And we mean any sort of change, not merely removal. If you replace the cat removal with an attempt to insert new cats, the result will be the same:
for (Cat cat: cats) {

   cats.add(new Cat("Salem Saberhagen"));
}

System.out.println(cats);
Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) at java.util.ArrayList$Itr.next(ArrayList.java:831) at Cat.main(Cat.java:25) We changed one operation to another, but the result didn't change: we get the same ConcurrentModificationException. It occurs precisely when we try breaking the rule above by changing the list while iterating over it. In Java, we need a special object called an iterator (Iterator class) to delete items while iterating over a collection. The Iterator class is responsible for safely iterating over the list of elements. It is quite simple, since it has only 3 methods:
  • hasNext() - returns true or false, depending on whether there is a next item in the list, or we have already reached the last one.
  • next() - returns the next item in the list
  • remove() - removes an item from the list
As you can see, the iterator is tailor-made for our needs, and at the same time there's nothing complicated about it. Suppose we want to check if there is a next element in our list, and display it if there is:
Iterator<Cat> catIterator = cats.iterator();// Create an iterator
while(catIterator.hasNext()) {// As long as there are elements in the list

   Cat nextCat = catIterator.next();// Get the next element
   System.out.println(nextCat);// Display it
}
Output: Cat{name='Thomas'} Cat{name='Behemoth'} Cat{name='Lionel Messi'} Cat{name='Fluffy'} As you can see, the ArrayList has already implemented a special method for creating an iterator: iterator(). Additionally, note that when we create an iterator, we specify the class of objects that it will work with (<Cat>). The bottom line is that an iterator easily handles our original task. For example, remove the cat named "Lionel Messi":
Iterator<Cat> catIterator = cats.iterator();// Create an iterator
while(catIterator.hasNext()) {// As long as there are elements in the list

   Cat nextCat = catIterator.next();// Get the next element
   if (nextCat.name.equals("Lionel Messi")) {
       catIterator.remove();// Delete the cat with the specified name
   }
}

System.out.println(cats);
Output: [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Fluffy'}] You may have noticed that we didn't specify either the index or the name in the iterator's remove() method! The iterator is smarter than it may appear: remove() removes the last element returned by the iterator. As you can see, it did just what we wanted it to do :) In principle, this is everything you need to know about removing elements from an ArrayList. Well, almost everything. In the next lesson, we'll look inside this class, and see what happens there during various method calls :) Until then!
Comments (34)
  • Popular
  • New
  • Old
You must be signed in to leave a comment
Anonymous #11274698
Level 8 , Gorzow Wielkopolski, Poland
20 July 2023, 14:03
"The iterator is smarter than it may appear: remove() removes the last element returned by the iterator. As you can see, it did just what we wanted it to do :)" But the last one is "Fluffy" not "Messi". And if this is true that means that "if instruction" is unnecessary beacause Iterator doesent search for "Lionel Messi" but simply remove last element from ArrayList
l.jargielo
Level 18 , Poland, Poland
2 January 2023, 11:13
Is thera a mistake in the last number of index? Cat[] cats = new Cat[4]; cats[0] = new Cat("Thomas"); cats[1] = new Cat("Behemoth"); cats[2] = new Cat("Lionel Messi"); cats[2] = new Cat("Fluffy");
Molo
Level 41 , Lublin, Poland
10 September 2022, 16:08
Pamiętajcie o "remove()" iteratora bo później się człowiek zastanawia jak usunąć element :] przy zadaniu przydaje się które będzie dalej
Rafał Papała
Level 22 , Gdańsk, Poland
8 September 2022, 08:43
My solution to moving null element to the end of array:
for (int i = 0; i < cats.length - 1; i++) {
       Cat temp = null; // temporary value for moving null
       if(cats[i] == null) {
           cats[i] = cats[i + 1]; // replaces index i (with null) with next index without null
           cats[i + 1] = temp; // swap next index value with null
       }
   }
Where:
Cat[] cats = new Cat[4];
cats[0] = new Cat("Thomas");
cats[1] = new Cat("Behemoth");
cats[2] = new Cat("Lionel Messi");
cats[3] = new Cat("Fluffy");

cats[1] = null;
Lisa
Level 41
1 August 2021, 11:42
Just to recap, the for-each loop throws a ConncurrentModificationException when an element of a collection is iterated and deleted at the same time. This is because the for-each loop uses an Iterator internally. To avoid the exception we would need to use this Iterator to remove the element, but it is not visible "outside" and therefore not usable by us users of this loop. Using a regular loop is still possible. You just need to manage the index yourself.
for (int i = 0; i < cats.size();)
    if (cats.get(i).name.equals("Behemoth"))
        cats.remove(cats.get(i));
    else
        i++;
Andy Lee
Level 10
2 March 2021, 08:37
使用迭代器以在迭代过程操作集合元素
ъуъ
Level 9 , Vilnius, Lithuania
8 October 2020, 12:57
That was more than enough cats for today...
Mariam
Level 9 , Columbus, United States
12 September 2020, 03:48
I still do not know how to: 1) copy fifteen element from the bottom of the ArrayList to the top of the ArrayList 2) delete those bottom ones
12 September 2020, 05:32
for(int i = 0;i < 15;++i){ list.add(0, list.get(list.size()); list.remove(list.size()); } I hope it helps you
Chang You
Level 47 , Santa Rosa, United States
22 December 2020, 20:59
Should be ?
list.add(0, list.get(list.size() - 1);
list.remove(list.size() -1 );
Aakankasha Sharma
Level 18 , Chandigarh, India
10 June 2020, 16:54
We could go another way and create a separate method:
public void deleteCat(Cat[] cats, int indexToDelete) {
   //...delete the cat corresponding to the index and move the elements
}
But this is also of little use: this method can only work with Cat objects, but not other types. But can't we create a function that accepts an array of Objects, more like Object[] object, int indexToDelete? What are the possible issues that may arise (one is that I'll have to create this function everytime) ? Also curiously, what implementation does the ArrayList use when remove(int index) function is called?
Lisa
Level 41
1 August 2021, 11:27
you could write a generic method like:
public static <T> void deleteFromArray(T[] arr, int indexToDelete) {
    arr[indexToDelete] = null;
    for (int i = indexToDelete + 1; i < arr.length; i++)
        arr[i - 1] = arr[i];
    arr[arr.length - 1] = null;
}
I've also fixed the not correctly working code above
Kent Hervey Software Engineer/Consult Expert
21 November 2019, 01:57
I love the humor in the name of this cat...from a funny TV show: cats.add(new Cat("Salem Saberhagen"));
Xiaobo H
Level 17 , Atlanta, United States
6 February 2020, 23:59
Wow...this is so beyond foreign learners. I did not pay any attention to the name of the cats. Thank you and thanks to Wiki! :)