IndexOutOfBoundsException for Kotlin for循环

我有两个相同大小的Kotlin列表, foodObjects: MutableList<ParseObject>?checked: MutableList<Boolean>? 。 我需要做一个for循环,每次checked一个元素为true时,从foodObjects获取objectId。 所以这是在Java中:

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

但是在科特林,我不知道为什么,有一些问题。 事实上,如果我这样做:

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

我有IndexOutOfBoundsException :我不知道为什么,它继续在foodObjects.size循环。 我也可以用过滤器和地图来做到这一点:

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

但是我给了同样的错误。 我需要停止使用这个如果:

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

得到它的作品。

每个人都可以告诉我为什么在Kotlin我需要这样做,在Java中它运作良好?

Kotlin的范围是包容性的,因此0..foodObjects!!.size0开始,以foodObjects.size结束,包括两端。 当您的循环尝试使用自己的大小索引列表时,这将导致异常,这比最大的有效索引多一个索引。

要创建一个不包含上限(如Java循环)的范围,可以使用until

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

如果您对您使用的集合进行了空检查,您也可以清理一下代码:

 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 } 

为了摆脱必须完全处理索引,你可以使用列表的indices属性(加上我使用索引操作符在这里,而不是调用):

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

你也可以使用forEachIndexed

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

看一下Kotlin文档中的范例:

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

如你看到的

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

将被打印。 所以,包括10。

您收集foodObjects的最高索引是(foodObjects.size() - 1)因为它从0开始。

所以,要解决你的问题,只要做到这一点:

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

写一个更好的方法是:

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

这样你就可以同时拥有元素和索引,不需要担心范围。

*我删除了简单的空检查。