user7418450
user7418450

Reputation: 51

Kotlin problem with deleting object in the loop

I have person objects that have a gender field objects the person adds to the list then I want to remove from the list people who have man


enum class Gender{
  woman, man
}

fun main(args: Array<String>) {

  data class Person(var name: String, var surname: String, var gender: Gender)

  val person1 = Person("Jan", "Kowalski", Gender.man)
  val person2 = Person("Paweł", "Pawelski", Gender.man)
  val person3 = Person("Ewa", "Miła", Gender.woman)
  val person4 = Person("Gosia", "Zemvba", Gender.woman)

  var PersonList = listOf<Person>(person1, person2, person3, person4).toMutableList()

  val listIterator2 = PersonList.iterator()
  while (listIterator2.hasNext()) {
      var tmp = listIterator2.next()
      if (tmp.gender == Gender.man) {
          println( "deleted  " + tmp)
          PersonList.remove(tmp)

      }
  }

}

in line var tmp = listIterator2.next() i have a error

Exception in thread "main" java.util.ConcurrentModificationException
    at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1012)
    at java.base/java.util.ArrayList$Itr.next(ArrayList.java:966)  
    at TmpKt.main(tmp.kt:19)

Upvotes: 1

Views: 2320

Answers (3)

Saeed Ir
Saeed Ir

Reputation: 2332

Iterators are not always helpful when another thread modifies the collection. I had tried many ways but then realized traversing the collection manually is much safer (backward for remove):

for (i in listPersons.size-1 downTo 0) {
    myList.getOrNull(i)?.apply {
       if (gender == Gender.man)
          listPersons.remove(this)
    }
}

Upvotes: 0

Michael Rush
Michael Rush

Reputation: 4340

Rather than manipulating the original list, you can produce a new list like:

  val personList = listOf<Person>(person1, person2, person3, person4)
  val personListUpdated = personList.filter { it.gender != Gender.man }

(or, as suggested by Tenfour04 above, removeAll or filterNot can also be used to invert the condition)

See this playground to try it yourself: https://pl.kotl.in/LGkr_cobj

Upvotes: 1

Tenfour04
Tenfour04

Reputation: 93629

You have to call remove on the iterator itself, not the list.

  val listIterator2 = PersonList.iterator()
  while (listIterator2.hasNext()) {
      var tmp = listIterator2.next()
      if (tmp.gender == Gender.man) {
          println( "deleted  " + tmp)
          listIterator2.remove()
      }
  }

It is easier to use removeAll() than to work with the iterator directly:

personList.removeAll { it.gender == Gender.man }

Upvotes: 2

Related Questions