2009-01-30 144 views
100

我正在编写一些使用Apache POI API的Scala代码。我想遍历从Sheet类获得的java.util.Iterator中包含的行。我想在for each样式循环中使用迭代器,所以我一直试图将它转换为本地Scala集合,但不会运气。在Scala中迭代Java集合

我看过Scala包装类/特性,但我看不到如何正确使用它们。如何在不使用详细的while(hasNext()) getNext()循环风格的情况下遍历Scala中的Java集合?

这是我写的基于正确答案代码:

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

我似乎无法为包括(VAL行线” < - rows){“没有解析器认为'<'字符是XML结束标记?反引号不起作用 – 2009-01-30 17:15:54

+0

您应该能够隐式转换为IteratirWrapper,从而为您节省一点点语法。 Google在Scala中进行隐式转换。 – 2009-01-30 18:01:34

回答

25

有一个包装类(scala.collection.jcl.MutableIterator.Wrapper )。所以,如果你定义

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

那么它将作为一个子类斯卡拉迭代器,所以你可以做foreach

+0

它应该是: scala.collection.jcl.MutableIterator.Wrapper – samg 2009-12-30 23:21:13

15

正确的答案是定义从Java的Iterator一些自定义类型的隐式转换。这种类型应实施代理底层Iteratorforeach方法。这将允许您使用Scala for -loop以及任何Java Iterator

4

您可以在Java集合转换为数组和使用:

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

或去和数组转换为斯卡拉列表:

val list = List.fromArray(array) 
237

从Scala 2.8开始,你所要做的就是导入JavaConversions对象,它已经声明了适当的转换。

import scala.collection.JavaConversions._ 

虽然这不适用于以前的版本。

9

对于Scala的2.10:

// Feature warning if you don't enable implicit conversions... 
import scala.language.implicitConversions 
import scala.collection.convert.WrapAsScala.enumerationAsScalaIterator 
5

使用Scala 2.10.4+(以及可能更早),可以隐式转换java.util.Iterator的[A]至scala.collection.Iterator [A]由导入scala.collection.JavaConversions.asScalaIterator。这里有一个例子:

object SpreadSheetParser2 extends App { 

    import org.apache.poi.hssf.usermodel.HSSFWorkbook 
    import java.io.FileInputStream 
    import scala.collection.JavaConversions.asScalaIterator 

    val ios = new FileInputStream("data.xls") 
    val workbook = new HSSFWorkbook(ios) 
    var sheet = workbook.getSheetAt(0) 
    val rows = sheet.rowIterator() 

    for (row <- rows) { 
    val cells = row.cellIterator() 
    for (cell <- cells) { 
     print(cell + ",") 
    } 
    println 
    } 

} 
2

如果你想避免implicits在scala.collection.JavaConversions可以使用scala.collection.JavaConverters明确转换。

scala> val l = new java.util.LinkedList[Int]() 
l: java.util.LinkedList[Int] = [] 

scala> (1 to 10).foreach(l.add(_)) 

scala> val i = l.iterator 
i: java.util.Iterator[Int] = [email protected] 

scala> import scala.collection.JavaConverters._ 
import scala.collection.JavaConverters._ 

scala> i.asScala.mkString 
res10: String = 12345678910 

注意使用asScala方法的Java Iterator转换为斯卡拉Iterator

JavaConverters自Scala 2.8.1开始提供。

1

如果您正在迭代大型数据集,那么您可能不希望将整个集合加载到内存中,并使用.asScala隐式转换。在这种情况下,一种方便的方法方法是实现scala.collection.Iterator特质

import java.util.{Iterator => JIterator} 

def scalaIterator[T](it: JIterator[T]) = new Iterator[T] { 
    override def hasNext = it.hasNext 
    override def next() = it.next() 
} 

val jIterator: Iterator[String] = ... // iterating over a large dataset 
scalaIterator(jIterator).take(2).map(_.length).foreach(println) // only first 2 elements are loaded to memory 

它类似的概念,但更简洁IMO :)

4

斯卡拉2.12.0不赞成scala.collection.JavaConversions,这样以来的2.12.0一个方式做这将是这样的:

import scala.collection.JavaConverters._ 

// ... 

for(k <- javaCollection.asScala) { 
    // ... 
} 

(注意输入,新的JavaConverters,过时的JavaConversions)