2011-09-28 20 views
13

Por favor, tengan paciencia, todavía soy bastante novato con Scala. Tengo el siguiente código:java.util.Iterator a Scala list?

private lazy val keys : List[String] = obj.getKeys().asScala.toList 

obj.getKeys devuelve un java.util.Iterator

Calling asScala, a través de JavaConverers (que es importado) de acuerdo con los documentos ..

java.util.Iterator <==> scala.collection.Iterator 

scala.collection.Iterator define

def toList : List[A] 

Basado en esto creo que esto debería funcionar, sin embargo er aquí está el error de compilación.

[scalac] <file>.scala:11: error: type mismatch; 
[scalac] found : List[?0] where type ?0 
[scalac] required: List[String] 
[scalac] private lazy val keys : List[String] = obj.getKeys().asScala.toList 
[scalac] one error found 

entiendo el parámetro de tipo o el iterador Java es una serie Java, y que yo estoy tratando de crear una lista de cadenas Scala, pero (quizás ingenuamente) pensaba que habría una conversión implícita.

Respuesta

10

Eso funcionaría si obj.getKeys() fuera un java.util.Iterator<String>. Supongo que no es así.

Si obj.getKeys() es sólo java.util.Iterator en forma cruda, no java.util.Iterator<String>, ni siquiera java.util.Iterator<?>, esto es algo Scala tienden a disgustos, pero de todos modos, no hay manera de Scala se escriba su expresión como List[String] si no tiene ninguna garantía obj.getKeys() contiene Cadena .

Si sabe que su iterador está en cuerdas, pero el tipo no lo dice, puede emitir:

obj.getKeys().asInstanceOf[java.util.Iterator[String]] 

(luego seguir con .asScala.toList)

Tenga en cuenta que, al igual que en java y debido al borrado de tipo, ese molde no se verificará (recibirá una advertencia). Si desea comprobar de inmediato que tiene cadenas, es posible que en lugar hacer

obj.getKeys().map(_.asInstanceOf[String]) 

que comprobará el tipo de cada elemento, mientras que usted repite para crear la lista

+1

¡Muchas gracias por la respuesta! parece que usted y Matthew Farwell están de acuerdo en su mayor parte. Hice lo que sugieres, obj.getKeys(). AsInstanceOf [java.util.Iterator [String]]. AsScala.toList y parece funcionar, y no recibí una advertencia de compilación. – rshepherd

24

No es necesario llamar asScala, es una conversión implícita:

import scala.collection.JavaConversions._ 

val javaList = new java.util.LinkedList[String]() // as an example 

val scalaList = javaList.iterator.toList 

Si realmente no tiene el parámetro de tipo de iterador, simplemente echarlo al tipo correcto:

javaList.iterator.asInstanceOf[java.util.Iterator[String]].toList 

EDITAR: Algunas personas prefieren no usar las conversiones implícitas en JavaConversions, pero usan los decoradores asScala/asJava en JavaConverters para hacer las conversiones más explícitas.

+0

Tiene razón, no hay ningún parámetro de tipo para el iterador que se devuelve desde el método getKeys(). Observación muy astuta, gracias. Aunque parece que necesito el asScala allí, en ese caso. Quizás hay algo más que me estoy perdiendo. – rshepherd

+0

La conversión implícita está en 'JavaConversions', pero no en' JavaConverters'. Eso usa 'asScala'. Muchas personas, incluida yo misma, preferimos que esta conversión sea explícita para evitar errores sutiles. –

+0

@Daniel Supongo que hacer cosas explícitas es una buena idea, gracias por la sugerencia. –

3

No me gusta las otras respuestas. Demonios, no me gusta nada que sugiera usar asInstanceOf a menos que no haya otra alternativa. En este caso, hay. Si hace esto:

private lazy val keys : List[String] = obj.getKeys().asScala.collect { 
    case s: String => s 
}.toList 

gira el Iterator[_] en un Iterator[String] forma segura y eficiente.

Cuestiones relacionadas