在 Scala 中迭代 Java 集合
Posted
技术标签:
【中文标题】在 Scala 中迭代 Java 集合【英文标题】:Iterating over Java collections in Scala 【发布时间】:2010-10-04 11:44:47 【问题描述】:我正在编写一些使用 Apache POI API 的 Scala 代码。我想遍历从 Sheet 类获得的 java.util.Iterator
中包含的行。我想在 for each
样式循环中使用迭代器,所以我一直在尝试将其转换为原生 Scala 集合,但没有成功。
我查看了 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)
【问题讨论】:
如果解析器认为“ 您应该能够隐式转换为 IteraterWrapper,从而为您节省大量语法。 Google 用于 Scala 中的隐式转换。 【参考方案1】:从 Scala 2.8 开始,您所要做的就是导入 JavaConversions 对象,该对象已经声明了适当的转换。
import scala.collection.JavaConversions._
这在以前的版本中不起作用。
【讨论】:
【参考方案2】:编辑: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)
// ...
(注意导入,new 是 JavaConverters,deprecated 是 JavaConversions)
【讨论】:
我在寻找“toScala”^_^!【参考方案3】:有一个包装类 (scala.collection.jcl.MutableIterator.Wrapper
)。所以如果你定义
implicit def javaIteratorToScalaIterator[A](it : java.util.Iterator[A]) = new Wrapper(it)
然后它将充当 Scala 迭代器的子类,因此您可以执行 foreach
。
【讨论】:
应该是:scala.collection.jcl.MutableIterator.Wrapper 这个答案在 Scala 2.8 中已经过时了;见***.com/questions/2708990/…【参考方案4】:这里的正确答案是定义从 Java 的 Iterator
到某个自定义类型的隐式转换。这种类型应该实现一个foreach
方法,该方法委托给底层Iterator
。这将允许您将 Scala for
-loop 与任何 Java Iterator
一起使用。
【讨论】:
【参考方案5】:对于 Scala 2.10:
// Feature warning if you don't enable implicit conversions...
import scala.language.implicitConversions
import scala.collection.convert.WrapAsScala.enumerationAsScalaIterator
【讨论】:
【参考方案6】:使用 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
【讨论】:
【参考方案7】:如果您正在迭代一个大型数据集,那么您可能不希望使用 .asScala
隐式转换将整个集合加载到内存中。在这种情况下,一种方便的方法是实现scala.collection.Iterator
trait
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 :)
【讨论】:
【参考方案8】:您可以将 Java 集合转换为数组并使用它:
val array = java.util.Arrays.asList("one","two","three").toArray
array.foreach(println)
或者继续将数组转换为 Scala 列表:
val list = List.fromArray(array)
【讨论】:
【参考方案9】:如果您想避免 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
。
JavaConverters 从 Scala 2.8.1 开始可用。
【讨论】:
我在您的示例中使用了import scala.collection.JavaConverters._
,然后使用了javaList.iterator().asScala
,它起作用了以上是关于在 Scala 中迭代 Java 集合的主要内容,如果未能解决你的问题,请参考以下文章