2009-06-22 5 views
14

Eine Java-API gibt java.util.Map<java.lang.String,java.lang.Boolean> zurück. Ich möchte, dass in einem so Map[String,Boolean]Konvertieren von von java.util.Map in eine Scala-Map

setzen sich vorstellen, die wir haben:

var scalaMap : Map[String,Boolean] = Map.empty 
val javaMap = new JavaClass().map() // Returns java.util.Map<java.lang.String,java.lang.Boolean> 

Sie nicht Map.empty ++ javaMap tun können, weil die ++ Methode nicht weiß, über Java-Karten. Ich habe versucht:

scalaMap = Map.empty ++ new collection.jcl.MapWrapper[String,Boolean] { 
    override def underlying = javaMap 
} 

und:

scalaMap = Map.empty ++ new collection.jcl.MapWrapper[java.lang.String,java.lang.Boolean] { 
    override def underlying = javaMap 
    } 

Diese beiden nicht kompilieren, weil der Generika - java.lang.String ist nicht das gleiche wie ein scala String.

Gibt es eine gute Möglichkeit, dies zu tun, außer die Karte manuell zu kopieren?

EDIT: Danke, alle guten Antworten, ich habe viel von allen gelernt. Allerdings habe ich einen Fehler gemacht, indem ich hier ein einfacheres Problem gestellt habe als das, was ich tatsächlich habe. Also, wenn Sie mir erlauben, werde ich die Frage verallgemeinern - Was die API tatsächlich zurückgibt, ist

java.util.Map<java.lang.String, java.util.Map<SomeJavaEnum,java.lang.String>> 

Und ich muss dazu bewegen Karte [String, Map [SomeJavaEnum, String]]

Es scheint nicht zu kompliziert zu sein, aber es fügt eine zusätzliche Stufe der Typ-Löschung hinzu, und die einzige Möglichkeit, dies auf eine Scala-Map zu verschieben, war das Tiefkopieren (mit einigen der unten vorgeschlagenen Techniken). Irgendwelche Hinweise? Ich habe mein Problem gelöst, indem ich eine implizite Konvertierung für meine genauen Typen definiert habe, so dass zumindest die Hässlichkeit in ihrer eigenen Eigenschaft verborgen ist, aber immer noch ein bisschen plump wirkt und das Ganze kopiert.

+0

ich ganz wie die Conversions antworten ich aus der scala-Benutzergruppe bekam. Ich muss nur nachsehen, ob es funktioniert ... Aber es ist jetzt viel zu spät hier, also werde ich bald zurück schreiben ... – George

Antwort

2

useJavaMap.scala

import test._ 
import java.lang.Boolean 
import java.util.{Map => JavaMap} 
import collection.jcl.MapWrapper 

object useJavaMap { 
    def main(args: Array[String]) { 
    var scalaMap : Map[String, Boolean] = Map.empty 
    scalaMap = toMap(test.testing()) 
    println(scalaMap) 
    } 

    def toMap[K, E](m: JavaMap[K, E]): Map[K, E] = { 
    Map.empty ++ new MapWrapper[K, E]() { 
     def underlying = m 
    } 
    } 
} 

test/test.java

package test; 

import java.util.*; 

public class test { 
    public static Map<String, Boolean> testing() { 
     Map<String, Boolean> x = new HashMap<String, Boolean>(); 
     x.put("Test",Boolean.FALSE); 
     return x; 
    } 
    private test() {} 
} 

Command

javac test\test.java 
scalac useJavaMap.scala 
scala useJavaMap 
> Map(Test -> false) 
+0

Weder und das funktioniert, fürchte ich. Dies sind generische Klassen - Map [String, Boolean] ist nicht dasselbe wie Map [java.lang.String, java.lang.Boolean], daher erhalten Sie: type mismatch; gefunden: java.lang.Object mit scala.collection.jcl.MapWrapper [String, Boolean] \t {...} erforderlich: Map [String, Boolean] – George

+0

hatte Zeit, es zu versuchen (das erste Beispiel verwendet wird). Volles Beispiel zur Verfügung gestellt – jitter

+0

Danke, 'Map.empty ++ JMapWrapper [K, V] (myJavaMap)' ist, was ich will! –

0

Ich glaube, ich habe eine teilweise Antwort ...

Wenn Sie die Java-Karte in eine Scala-Map mit den Java-Typen konvertieren. Sie können dann auf eine scala Karte von scala Arten Karte zeigen:

val javaMap = new java.util.TreeMap[java.lang.String, java.lang.Boolean] 
val temp = new collection.jcl.MapWrapper[java.lang.String,java.lang.Boolean] { 
    override def underlying = javaMap 
} 
val scalaMap = temp.map{ 
    case (k, v) => (k.asInstanceOf[String] -> v.asInstanceOf[Boolean]) 
} 

Der Fehler in diesem Plan ist, dass die Art der scalaMap ist Iterable [(java.lang.String, Boolean)] nicht eine Karte. Ich fühle mich so nah, kann jemand klüger als ich die letzte Aussage reparieren, um diese Arbeit zu machen ?!

6

A Scala String ist ein java.lang.Stringaber eine Scala Booleannicht ist ein java.lang.Boolean.Daraus ergibt sich die folgende Arbeiten:

import collection.jcl.Conversions._ 
import collection.mutable.{Map => MMap} 
import java.util.Collections._ 
import java.util.{Map => JMap} 

val jm: JMap[String, java.lang.Boolean] = singletonMap("HELLO", java.lang.Boolean.TRUE) 

val sm: MMap[String, java.lang.Boolean] = jm //COMPILES FINE 

Aber das Problem ist immer noch das Problem mit dem Boolean Unterschied. Sie müssen zu „falten“, um die Java-Karte in das scala ein: versuchen Sie es erneut die Boolean Typ Scala mit:

val sm: MMap[String, Boolean] = collection.mutable.Map.empty + ("WORLD" -> false) 
val mm = (sm /: jm) { (s, t2) => s + (t2._1 -> t2._2.booleanValue) } 

Dann mm eine scala Karte den Inhalt der ursprünglichen scala Karte enthält und was in der war Java Karte

+0

Tatsächlich konvertiert Ihre Antwort in veränderbare Karte, während der Autor nach unveränderlichen fragte. –

11

mindestens mit Scala 2.9.2 gibt es einen einfacheren Weg, um mit den Sammlungen Konvertierungen: import „Import collection.JavaConversions._“ und verwendet „toMap“.

Beispiel:

// show with Java Map: 

scala> import java.util.{Map=>JMap} 
scala> val jenv: JMap[String,String] = System.getenv() 
jenv: java.util.Map[String,String] = {TERM=xterm, ANT_OPTS=-Xmx512m ...} 

scala> jenv.keySet() 
res1: java.util.Set[String] = [TERM, ANT_OPTS...] 

// Now with Scala Map: 

scala> import collection.JavaConversions._ 
scala> val env: Map[String,String] = System.getenv.toMap // <--- TADA <--- 
env: Map[String,String] = Map(ANT_OPTS -> -Xmx512m, TERM -> xterm ...) 

// Just to prove it's got Scala functionality: 

scala> env.filterKeys(_.indexOf("TERM")>=0) 
res6: scala.collection.immutable.Map[String,String] = Map(TERM -> xterm, 
    TERM_PROGRAM -> iTerm.app, ITERM_PROFILE -> Default) 

Es arbeitet mit einem java.util.map von String Boolean in Ordnung.