I have a ListBuffer[MyClass]
and use it as a queue.
Now consider the following code:
private def buildChunks(): Unit =
{
for(a <- 0 until buildQueue.size)
{
val chunk: Chunk = buildQueue(a)
chunk.init()
// buildQueue -= chunk
// buildQueue.remove(a)
}
}
My problem with understanding boils down to these two lines:
buildQueue -= chunk
buildQueue.remove(a)
Both of them yield an ArrayOutOfBoundsException
if used (of course mutually exclusive I did not use them both at once!)
As I said (and as the name implies) the ListBuffer is used as a queue, so if one item is processed I want to remove it from the list.
I do not understand why any of these lines throws an ArrayOutOfBoundsException
How am I supposed to remove an Item then?
If you can make me understand this, I would gladly use a prettier approach such as:
val chunk: Chunk = buildQueue.remove(a)
but of course this doesn't work
You problem would be that you are changing a mutable collection while iterating over it's values.
In for(a <- 0 until buildQueue.size)
the value of buildQueue.size
is evaluated once because 0 until buildQueue.size
creates an immutable Seq[Int]
.
Now, if your list buffer initially has a size of 5 and you remove one element, it will end up with a size of 4. However, your loop will iterate until index 4, which is no longer present in the list buffer.
One way to fix this would be using a recursive function:
private def buildChunks(): Unit = {
@tailrec
def buildHead(): Unit = {
buildQueue.headOption match {
case None ⇒
() // end of recursion
case Some(chunk) ⇒
chunk.init()
buildQueue -= chunk
buildHead()
}
}
buildHead()
}
UPDATE:
As pointed out by Teolha you could as well just do:
private def buildChunks(): Unit = {
buildQueue.foreach(_.init())
buildQueue.clear()
}
which is much shorter and probably more efficient.
However, it would not build chunks appended to the queue concurrently while buildChunks()
is executed and in fact might remove any chunks added after foreach
is started.