英文:
Does Kotlin's version of Java's for each have the same limitations?
问题
我目前正在从Java学习Kotlin。在Java中,执行以下操作:
for(String s:stringList){
if(condition == true) stringList.remove(s);
}
是行不通的,因为你只能使用for each来读取数据,无法进行修改。这个规则在Kotlin中是否也适用?
英文:
I'm currently learning Kotlin coming from Java. In Java, doing
for(String s:stringList){
if(condition == true) stringList.remove(s);
}
doesn't work, as you can only read data with for each. Does this also apply to Kotlin?
答案1
得分: 2
这与Java中的限制相同 - 当您在迭代集合时,只能通过Iterator
的remove()
方法来修改它
> 从基础集合中删除此迭代器返回的最后一个元素(可选操作)。每次调用next()只能调用一次此方法。如果在迭代进行中以除调用此方法之外的任何方式修改基础集合,则迭代器的行为是未指定的。
Kotlin也有自己的等效方法(请注意,Kotlin使用可变和不可变列表的概念,因此您只能对MutableList
执行此操作)
foreach
/ 增强的 for
结构的问题在于它不会公开您需要调用 remove()
的Iterator
,而且您不能在集合本身上调用 remove()
。Kotlin也是如此 - 所以您的选择基本上是
- 使用
for
/forEach
(但不能修改集合) - 调用集合的
iterator()
方法并自己进行迭代(现在您可以在其上调用remove()
,但受到我引用的限制) - 避免可变性并生成新的集合
最后一个选项是Kotlin鼓励您采取的方法 - 与其修改集合,不如尝试使用不可变的集合并将其转换为新的集合:
stringList.filterNot { condition }
如果您熟悉所有的集合函数(是的,有很多),您将了解将A转换为B的方式,以及可帮助您执行此操作的便利函数(例如filterTo
,它允许您提供一个MutableList
来存储要保留的项目)。
不过,如果您确实想要直接修改可变集合,那是可能的,但您必须自己管理,因为这本质上是危险的,系统不能保证您的安全操作。
英文:
It's the same restriction as in Java - when you're iterating over a collection, you're limited to modifying it through the Iterator
's remove()
method
> Removes from the underlying collection the last element returned by this iterator (optional operation). This method can be called only once per call to next(). The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method.
Kotlin has its own equivalent (bearing in mind Kotlin uses the concept of mutable and immutable lists, so you can only do this with a MutableList
)
The problem with the foreach
/ enhanced for
structure is it doesn't expose the Iterator
you need to call remove()
on, and you're not allowed to call remove()
on the collection itself. And Kotlin's the same - so your options are basically
- use
for
/forEach
(but you can't modify the collection) - call the collection's
iterator()
method and iterate over it yourself (now you can callremove()
on it, with the restrictions I quoted) - avoid mutability and produce a new collection
The last one is what you're encouraged to do in Kotlin - instead of modifying a collection, try to use immutable ones and transform them into new collections instead:
stringList.filterNot { condition }
If you get familiar with all the collection functions (yeah, there are a lot of them) you'll get an idea of the ways you can transform A to B, and the convenience functions that are there to help you do it (e.g. filterTo
which lets you provide a MutableList
to populate with the items you want to keep).
If you do want to modify mutable collections in place though, it's possible but you have to manage it yourself, because it's inherently dangerous and the system can't guarantee you're doing it safely.
答案2
得分: 1
是的,如果您在Kotlin中重写这段代码,您将会遇到相同的并发修改问题:
for (s in stringList) {
if(condition == true) stringList.remove(s)
}
为了避免这个问题,您可以从可变列表获取一个可变迭代器,并使用它在迭代过程中移除元素。但与Java不同的是,您不必使用hasNext()
/next()
调用手动进行迭代 — 您可以在相同的for
循环中使用它来迭代:
val iterator = stringList.iterator()
for (s in iterator) {
if (condition == true) iterator.remove()
}
英文:
Yes, if you rewrite this code in Kotlin, you'll get the same concurrent modification problem:
for (s in stringList) {
if(condition == true) stringList.remove(s)
}
To avoid this problem, you can obtain a mutable iterator from a mutable list and use it to remove elements on the go. But unlike Java, you don't have to iterate it manually with hasNext()
/next()
calls — you can use the same for
operator for iterating it:
val iterator = stringList.iterator()
for (s in iterator) {
if (condition == true) iterator.remove()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论