在 Scala 中迭代 Java 集合

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/495741/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 15:21:36  来源:igfitidea点击:

Iterating over Java collections in Scala

javascalacollectionsscala-java-interop

提问by BefittingTheorem

I'm writing some Scala code which uses the Apache POIAPI. I would like to iterate over the rows contained in the java.util.Iteratorthat I get from the Sheet class. I would like to use the iterator in a for eachstyle loop, so I have been trying to convert it to a native Scala collection but will no luck.

我正在编写一些使用Apache POIAPI 的Scala 代码。我想遍历java.util.Iterator我从 Sheet 类获得的 中包含的行。我想在for each样式循环中使用迭代器,所以我一直在尝试将它转换为原生 Scala 集合,但没有成功。

I have looked at the Scala wrapper classes/traits, but I can not see how to use them correctly. How do I iterate over a Java collection in Scala without using the verbose while(hasNext()) getNext()style of loop?

我已经查看了 Scala 包装器类/特征,但我看不出如何正确使用它们。如何在不使用冗长while(hasNext()) getNext()的循环样式的情况下迭代 Scala 中的 Java 集合?

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

采纳答案by Fabian Steeg

There is a wrapper class (scala.collection.jcl.MutableIterator.Wrapper). So if you define

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

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

then it will act as a sub class of the Scala iterator so you can do foreach.

然后它将充当 Scala 迭代器的子类,因此您可以执行foreach.

回答by Daniel Spiewak

The correct answer here is to define an implicit conversion from Java's Iteratorto some custom type. This type should implement a foreachmethod which delegates to the underlying Iterator. This will allow you to use a Scala for-loop with any Java Iterator.

这里的正确答案是定义从 JavaIterator到某些自定义类型的隐式转换。这种类型应该实现一个foreach委托给底层Iterator. 这将允许您对for任何 Java使用 Scala循环Iterator

回答by Fabian Steeg

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

您可以将 Java 集合转换为数组并使用它:

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

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

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

val list = List.fromArray(array)

回答by ttonelli

As of Scala 2.8, all you have to do is to import the JavaConversions object, which already declares the appropriate conversions.

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

import scala.collection.JavaConversions._

This won't work in previous versions though.

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

回答by F. P. Freely

For Scala 2.10:

对于 Scala 2.10:

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

回答by F. P. Freely

With Scala 2.10.4+ (and possibly earlier) it is possible to implicitly convert java.util.Iterator[A] to scala.collection.Iterator[A] by importing scala.collection.JavaConversions.asScalaIterator. Here is an example:

使用 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
  }

}

回答by kilo

If you would like to avoid the implicits in scala.collection.JavaConversionsyou can use scala.collection.JavaConvertersto convert explicitly.

如果您想避免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

Note the use of the asScalamethod to convert the Java Iteratorto a Scala Iterator.

请注意使用该asScala方法将 Java 转换Iterator为 Scala Iterator

The JavaConverters have been available since Scala 2.8.1.

JavaConverters 从 Scala 2.8.1 开始可用。

回答by Max

If you are iterating through a large dataset, then you probably don't want to load whole collection into memory with .asScalaimplicit conversion. In this case, a handy way approach is to implement scala.collection.Iteratortrait

如果您正在遍历大型数据集,那么您可能不想通过.asScala隐式转换将整个集合加载到内存中。在这种情况下,一个方便的方法是实现scala.collection.Iteratortrait

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

It has similar concept but less verbose IMO :)

它有类似的概念,但不那么冗长 IMO :)

回答by antonone

Edit: Scala 2.13.0 deprecates scala.collection.JavaConverters, so since 2.13.0 you need to use scala.jdk.CollectionConverters.

编辑:Scala 2.13.0 已弃用scala.collection.JavaConverters,因此自 2.13.0 起您需要使用scala.jdk.CollectionConverters.

Scala 2.12.0 deprecates scala.collection.JavaConversions, so since 2.12.0 one way of doing this would be something like:

Scala 2.12.0 弃用scala.collection.JavaConversions,因此从 2.12.0 开始,这样做的一种方法是:

import scala.collection.JavaConverters._

// ...

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

(notice the import, new is JavaConverters, deprecated is JavaConversions)

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