如何在Scala中将枚举转换为Seq / List?

问题描述 投票:24回答:4

我正在编写一个servlet,需要从请求中获取所有参数。我发现request.getParameterNames返回了java.util.Enumeration,因此我必须将代码编写为:

val names = request.getParameterNames
while(names.hasMoreElements) {
    val name = names.nextElement
}

我想知道有什么方法可以将Enumeration转换为Seq/List,然后可以使用map方法?

scala enumeration
4个回答
29
投票

您可以建立一个包装器:

val nameIterator = new Iterator[SomeType] { def hasNext = names.hasMoreElements; def next = names.nextElement }

或者,最后,这是内置方法,在这种情况下可能使用的方法:

val nameIterator = new scala.collection.JavaConversions.JEnumerationWrapper(names)

使用隐式:

我还有一个。如果您导入

import scala.collection.JavaConversions._

您可以隐式地执行此操作(并且您还将获得其他Java同事的隐式转换)

request.getParameterNames.map(println)

它就可以工作。

连续使用Iterator:

您可能会想像使用此答案的较早版本一样,使用Iterator.continually构建迭代器:

val nameIterator = Iterator.continually((names, names.nextElement)).takeWhile(_._1.hasMoreElements).map(_._2)

但是它是不正确的,因为枚举器的最后一个元素将被丢弃。原因是hasMoreElement中的takeWhile调用是在nextElement中的调用continually之后执行的,因此丢弃了最后一个值。


31
投票

当前最佳实践(自2.8.1开始)是使用scala.collection.JavaConverters

该类与JavaConversions稍有不同,因为转换不是完全自动的,可以提供更多控制权((这是一件好事)

import collection.JavaConverters._
val names = ...
val nameIterator = names.asScala

使用此机制,您将通过asScala/asJava方法获得大多数集合类型的适当且类型安全的转换。


1
投票

关于Debilski的答案的评论,即Iterator.continually方法是错误的,因为它错过了最后一个条目。这是我的测试:

val list = new java.util.ArrayList[String]
list.add("hello")
list.add("world")
val en = java.util.Collections.enumeration(list)
val names = Iterator.continually((en, en.nextElement)).takeWhile(_._1.hasMoreElements).map(_._2)
    .foreach { name => println("name=" + name) }

输出是

name=hello

缺少第二项(名称=世界)!

我通过使用JavaConversions.enumerationAsScalaIterator来使它正常工作,正如其他人所提到的。

注意,我没有足够的代表来直接评论Debilski的帖子。


0
投票

我不同意任何其他答案,但我必须添加类型强制转换才能使其在Scala 2.9.2和Java 7中进行编译。

import scala.collection.JavaConversions._
...
val names=request.getParameterNames.asInstanceOf[java.util.Enumeration[String]].toSet
© www.soinside.com 2019 - 2024. All rights reserved.