在 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
Iterating over Java collections in Scala
提问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.Iterator
that I get from the Sheet class. I would like to use the iterator in a for each
style 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 Iterator
to some custom type. This type should implement a foreach
method 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 asScala
method to convert the Java Iterator
to 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 .asScala
implicit conversion. In this case, a handy way approach is to implement scala.collection.Iterator
trait
如果您正在遍历大型数据集,那么您可能不想通过.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
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)