Как конфертировать из java.util.Map в карту Scala - PullRequest
14 голосов
/ 22 июня 2009

Java API возвращает java.util.Map<java.lang.String,java.lang.Boolean> ;. Я хотел бы поместить это в Map[String,Boolean]

Итак, представьте, что у нас есть:

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

Вы не можете сделать Map.empty ++ javaMap, потому что метод ++ не знает о картах Java. Я попробовал:

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

и

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

Они оба не компилируются из-за обобщений - java.lang.String не совпадает со строкой scala.

Есть ли хороший способ сделать это, кроме копирования карты вручную?

РЕДАКТИРОВАТЬ: Спасибо, все хорошие ответы, я многому научился у всех. Однако я допустил ошибку, разместив здесь более простую проблему, чем та, которая у меня есть на самом деле. Итак, если вы позволите мне, я обобщу вопрос - что API на самом деле возвращает

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

И мне нужно переместить это в Map [String, Map [SomeJavaEnum, String]]

Возможно, это не слишком сложное явление, но оно добавляет дополнительный уровень стирания типов, и единственный способ, которым я обнаружил перемещение этого на карту Scala, - это его глубокое копирование (используя некоторые предложено ниже). Есть какие-нибудь намеки? Я вроде как решил свою проблему, определив неявное преобразование для моих точных типов, так что, по крайней мере, уродство скрыто в его собственной черте, но все же кажется немного неуклюжимым, копируя всю партию.

Ответы [ 4 ]

11 голосов
/ 31 августа 2012

По крайней мере в Scala 2.9.2 есть более простой способ преобразования коллекций: импортировать "import collection.JavaConversions._" и использовать "toMap".

Пример:

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

Отлично работает с java.util.map String to Boolean.

6 голосов
/ 22 июня 2009

Scala String - это java.lang.String , но Scala Boolean - это не a java.lang.Boolean. Отсюда и следующие работы:

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

Но ваша проблема по-прежнему связана с разницей Boolean. Вам придется «сложить» карту Java в Scala: попробуйте еще раз, используя тип Scala Boolean:

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

Тогда mm - это карта скалы, содержащая содержимое исходной карты скалы плюс то, что было в карте Java

2 голосов
/ 22 июня 2009

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.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() {}
}

Commandline

javac test\test.java
scalac useJavaMap.scala
scala useJavaMap
> Map(Test -> false)
0 голосов
/ 22 июня 2009

Я думаю, что у меня есть частичный ответ ...

Если вы конвертируете карту Java в карту скалы с типами Java. Затем вы можете сопоставить его с картой scala типов scala:

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

Недостатком этого плана является то, что тип scalaMap является Iterable [(java.lang.String, Boolean)], а не картой. Я чувствую себя так близко, может кто-нибудь умнее меня исправить последнее заявление, чтобы это сработало?!

...