views:

6826

answers:

5

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 can not see how to use them correctly. So can anyone help me iterate over a Java collection in Scala without using the verbose while(hasNext()) getNext() style of loop?

Thanks

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)
        }
    }
}

+9  A: 

The first answer here is literally copy/paste from my blog. Regardless, 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.

Daniel Spiewak
+1  A: 

You could convert the Java collection to an array and use that:

val array = java.util.Arrays.asList("one","two","three").toArray
array.foreach(println)

Or go on and convert the array to a Scala list:

val list = List.fromArray(array)
Fabian Steeg
+8  A: 

There is a wrapper class (scala.collections.jcl.MutableIterator.Wrapper). so if you define

implicit def javaIteratorToScalaIterator[A](it : java.util.Iterator[A]) = new Wrapper(it)

it will act as a sub class of the scala Iterator so you can do foreach.

I couldn't find an implicit conversion for this already in the scala libraries, please tell me if you find it.

It should read: scala.collection.jcl.MutableIterator.Wrapper
samg
This answer is obsolete in Scala 2.8; see http://stackoverflow.com/questions/2708990/whats-the-new-way-to-iterate-over-a-java-map-in-scala-2-8-0
Alex R
+1  A: 

Not sure if it's clear, but James/stevendick's answer is correct (even though I can't vote it up and don't seem to be able to comment on it, apparently because I am new).

Here is some code of mine:

// this is the wrapper
import scala.collection.jcl.MutableIterator.Wrapper

// this is the magic implicit bit
implicit def javaIteratorToScalaIterator[A](it : java.util.Iterator[A]) = new Wrapper(it)

// this is a Set from Java
val CHARSETS = Charset.availableCharsets.keySet

// the magic implicit bit is put here automatically
for (charset <- CHARSETS.iterator) {
...
}

// alternatively, and equivalently, you could skip the implicit bit and do:
for (charset <- Wrapper(CHARSETS.iterator)) {
...
}

I suspect this could be improved further - seems odd that I need to have ".iterator" for example.

Andrew

andrew cooke
Thanks for the answer Andrew, I have up voted James/stevendicks answer
Brian Heylin
+19  A: 

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.

ttonelli