2009-01-30 126 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)