2017-07-26 2 views
0

J'ai deux liste dans Kotlin, de la même taille, foodObjects: MutableList<ParseObject>? et checked: MutableList<Boolean>?. Je dois faire un cycle et obtenir l'objectId de foodObjects chaque fois qu'un élément de checked est vrai. Il est donc cela en Java:IndexOutOfBoundsException pour for-loop dans Kotlin

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

mais Kotlin, je ne sais pas pourquoi, il y a quelques problèmes. En fait, si je fais ceci:

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

} 

J'ai IndexOutOfBoundsException: Je ne sais pas pourquoi, il continue le cycle aussi foodObjects.size. Je pourrais le faire aussi avec filtre et carte:

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

mais je donne la même erreur. Je dois l'arrêter en utilisant si:

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

pour que cela fonctionne.

Tout le monde pourrait me dire pourquoi dans Kotlin je dois le faire, quand en Java cela fonctionne bien?

Répondre

9

Les plages de Kotlin sont incluses, donc 0..foodObjects!!.size commence à 0 et se termine à foodObjects.size, incluant les deux extrémités. Cela provoque l'exception lorsque votre boucle tente d'indexer la liste avec sa propre taille, qui est un de plus que le plus grand index valide.

Pour créer une gamme qui ne comprend pas la limite supérieure (comme votre boucle Java), vous pouvez utiliser until:

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

Vous pouvez également nettoyer votre code un peu si vous avez chèques nuls sur les collections que vous utilisez à l'avant:

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 
} 

Et pour se débarrasser d'avoir à gérer des index tout à fait, vous pouvez utiliser la propriété indices d'une liste (plus j'utiliser la opérateur d'indexation ici au lieu de get appels):

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

Vous pouvez également utiliser forEachIndexed:

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

merci, j'ai pensé que c'était similaire à Java, maintenant j'ai compris! – ste9206

+0

désolé pour ma question, mais comment utiliser cette structure dans un recyclerview? J'ai trouvé le même problème – ste9206

+0

Je ne suis pas sûr de ce que votre problème est en ce qui concerne un RecyclerView, mais vous devriez le poster comme une nouvelle question. – zsmb13

1

Jetez un oeil à cet exemple de la documentation Kotlin pour ranges:

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

Comme vous pouvez voir

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

seront imprimés. Donc, le 10 est inclus.

L'index le plus élevé de votre collection foodObjects est (foodObjects.size() - 1) car il commence par 0.

Donc, pour résoudre votre problème, faites ceci:

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

Une meilleure façon d'écrire ce serait:

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

De cette façon, vous avez l'élément et l'indice à la fois et n'a pas besoin de s'inquiéter des gammes.

* J'ai supprimé les vérifications de null pour plus de simplicité.