Iterating over Java collections in Scala
I'm writing some Scala code which uses the Apache POI API. I would like to iterate over the rows contained in the java.util.Iterator
that I get from the Sheet class. I would like to use the iterator in a for each
style loop, so I have been trying to convert it to a native Scala collection but will no luck.
I have looked at the Scala wrapper classes/traits, but I can not see how to use them correctly. How do I iterate over a Java collection in Scala without using the verbose while(hasNext()) getNext()
style of loop?
Here's the code I wrote based on the correct answer:
class IteratorWrapper[A](iter:java.util.Iterator[A])
{
def foreach(f: A => Unit): Unit = {
while(iter.hasNext){
f(iter.next)
}
}
}
object SpreadsheetParser extends Application
{
implicit def iteratorToWrapper[T](iter:java.util.Iterator[T]):IteratorWrapper[T] = new IteratorWrapper[T](iter)
override def main(args:Array[String]):Unit =
{
val ios = new FileInputStream("assets/data.xls")
val workbook = new HSSFWorkbook(ios)
var sheet = workbook.getSheetAt(0)
var rows = sheet.rowIterator()
for (val row <- rows){
println(row)
}
}
}
As of Scala 2.8, all you have to do is to import the JavaConversions object, which already declares the appropriate conversions.
import scala.collection.JavaConversions._
This won't work in previous versions though.
Edit: Scala 2.13.0 deprecates scala.collection.JavaConverters
, so since 2.13.0 you need to use scala.jdk.CollectionConverters
.
Scala 2.12.0 deprecates scala.collection.JavaConversions
, so since 2.12.0 one way of doing this would be something like:
import scala.collection.JavaConverters._
// ...
for(k <- javaCollection.asScala) {
// ...
}
(notice the import, new is JavaConverters, deprecated is JavaConversions)
There is a wrapper class (scala.collection.jcl.MutableIterator.Wrapper
). So if you define
implicit def javaIteratorToScalaIterator[A](it : java.util.Iterator[A]) = new Wrapper(it)
then it will act as a sub class of the Scala iterator so you can do foreach
.
The correct answer here is to define an implicit conversion from Java's Iterator
to some custom type. This type should implement a foreach
method which delegates to the underlying Iterator
. This will allow you to use a Scala for
-loop with any Java Iterator
.
For Scala 2.10:
// Feature warning if you don't enable implicit conversions...
import scala.language.implicitConversions
import scala.collection.convert.WrapAsScala.enumerationAsScalaIterator