IndexOutOfBoundsException para for-loop en Kotlin

Tengo dos lists en Kotlin, del mismo tamaño, foodObjects: MutableList<ParseObject>? y checked: MutableList<Boolean>? . Necesito hacer un ciclo for y get el objectId de foodObjects cada vez que un elemento de checked es verdadero. Entonces es esto en Java:

  for(int i = 0; i< foodObjects.size(); i++) { //here } 

pero en Kotlin, no sé por qué, hay algunos problemas. De hecho, si hago esto:

  for(i in 0..foodObjects!!.size) { if (checked?.get(i) == true) { objectsId?.add(foodObjects.get(i).objectId) } } 

Tengo IndexOutOfBoundsException : no sé por qué, continúa el ciclo también en foodObjects.size . Podría hacerlo también con filter y map:

 (0..foodObjects!!.size) .filter { checked?.get(it) == true } .forEach { objectsId?.add(foodObjects.get(it).objectId) } 

pero estoy dando el mismo error. Necesito detenerlo usando esto si:

  for(i in 0..foodObjects!!.size) { if(i < foodObjects.size) { if (checked?.get(i) == true) { objectsId?.add(foodObjects.get(i).objectId) } } } 

para que funcione

Todos podrían decirme por qué en Kotlin necesito hacerlo, cuando en Java funciona bien.

Los ranges en Kotlin son inclusivos, por 0..foodObjects!!.size tanto el 0..foodObjects!!.size Comienza en 0 y termina en foodObjects.size , incluidos ambos extremos. Esto provoca la exception cuando su bucle intenta indexar la list con su propio tamaño, que es uno más que el índice válido más grande.

Para crear un range que no incluya el límite superior (como su bucle de Java), puede usar until :

 for(i in 0 until foodObjects!!.size) { // ... } 

También podría limpiar su código un poco si hiciera verificaciones nulas en las collections que está utilizando por adelantado:

 if (foodObjects != null && checked != null && objectsId != null) { for (i in 0 until foodObjects.size) { if (checked.get(i) == true) { objectsId.add(foodObjects.get(i).objectId) } } } else { // handle the case when one of the lists is null } 

Y para deshacerse de tener que manejar los índices por completo, puede usar los indices propiedad de una list (además, utilizo el operador de indexing aquí en lugar de get llamadas):

 for (i in foodObjects.indices) { if (checked[i]) { objectsId.add(foodObjects[i].objectId) } } 

También forEachIndexed usar forEachIndexed :

 foodObjects.forEachIndexed { i, foodObject -> if (checked[i]) { objectsId.add(foodObject.objectId) } } 

Eche un vistazo a este ejemplo de la documentation de Kotlin para ranges :

 if (i in 1..10) { // equivalent of 1 <= i && i <= 10 println(i) } 

Como puedes ver

1, 2, 3, 4, 5, 6, 7, 8, 9, 10

será impreso. Entonces, el 10 está incluido.

El índice más alto de su colección foodObjects es (foodObjects.size() - 1) porque comienza con 0.

Entonces, para solucionar su problema, solo haga esto:

 for(i in 0..(foodObjects.size - 1)) { // ... } 

Una mejor forma de escribir esto sería:

 for((i, element) in foodObjects.withIndex()){ // do something with element println("The index is $i") } 

De esta forma, tiene el elemento y el índice a la vez y no necesita preocuparse por los ranges.

* Eliminé las comprobaciones nulas por simplicidad.