在Scala中遍历Java集合

116
我正在编写一些使用Apache POI API的Scala代码。 我想要迭代Sheet类中包含的java.util.Iterator中的行。 我想在for each风格的循环中使用迭代器,因此我一直在尝试将其转换为本地Scala集合,但没有成功。
我已经查看了Scala包装类/特征,但是我无法正确使用它们。 如何在Scala中迭代Java集合而不使用冗长的while(hasNext()) getNext()循环样式?
以下是我根据正确答案编写的代码:
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)
        }
    }
}

我似乎无法包含行 "for (val row <- rows){",因为解析器认为 '<' 字符是 XML 结束标记?反引号不起作用。 - BefittingTheorem
你应该能够隐式地转换为IteratirWrapper,这样可以节省相当多的语法。在Scala中搜索隐式转换。 - Daniel Spiewak
9个回答

259

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

import scala.collection.JavaConversions._

但是这在以前的版本中不起作用。


36

编辑:Scala 2.13.0 废弃了 scala.collection.JavaConverters,所以从2.13.0开始,您需要使用 scala.jdk.CollectionConverters

Scala 2.12.0 废弃了 scala.collection.JavaConversions,因此从2.12.0开始,做到这一点的一种方法是:

import scala.collection.JavaConverters._

// ...

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

(注意导入,新的是JavaConverters,弃用的是JavaConversions)


3
我正在寻找“toScala” ^_^! - Profiterole

29

有一个包装类(scala.collection.jcl.MutableIterator.Wrapper)。因此,如果您定义

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

那么它将作为Scala迭代器的子类,因此您可以执行foreach操作。


应该是: scala.collection.jcl.MutableIterator.Wrapper - samg
37
在Scala 2.8中,此答案已过时;请参见https://dev59.com/7nE85IYBdhLWcg3wkkfK。 - Alex R

15

这里的正确答案是定义一种从Java的Iterator到某些自定义类型的隐式转换。该类型应实现一个foreach方法,该方法委托给底层的Iterator。这将允许您在任何Java Iterator中使用Scala for-loop。


9

对于Scala 2.10版本:

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

6

如果你正在遍历大型数据集,那么你可能不想使用.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

它的概念类似,但在我看来不那么冗长 :)

5

使用Scala 2.10.4+(以及可能的早期版本),通过导入scala.collection.JavaConversions.asScalaIterator,可以将java.util.Iterator[A]隐式转换为scala.collection.Iterator[A]。以下是一个示例:

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
  }

}

4
你可以将Java集合转换为数组并使用它:
val array = java.util.Arrays.asList("one","two","three").toArray
array.foreach(println)

或者将数组转换为Scala列表:

val list = List.fromArray(array)

2
如果您想避免使用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] = java.util.LinkedList$ListItr@11eadcba

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

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

请注意使用asScala方法将Java Iterator转换为Scala Iterator
自Scala 2.8.1起,JavaConverters已经可用。

1
我使用了 import scala.collection.JavaConverters._,然后从你的示例中使用了 javaList.iterator().asScala,它起作用了。 - kosiara - Bartosz Kosarzycki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接