Подтвердить что ты не робот

Как заполнить java.util.HashMap на лету от Scala кода?

Я тестирую код Java с помощью ScalaTest и хотел бы заполнить java.util.HashMap в том же самом заявлении, которое он объявит. Возможно ли это сделать в Scala?

4b9b3361

Ответ 1

Есть несколько способов сделать это, только некоторые из них появились в ответах до сих пор.

Метод первый: Так как java.util.HashMap имеет конструктор HashMap(Map<? extends K,? extends V> m), вы можете передать ему действительную карту Java. И вы можете сделать это тривиально с помощью Scala полезно JavaConversions:

scala> import scala.collection.JavaConversions._
import scala.collection.JavaConversions._

scala> val myMap = Map(1->"Hi",2->"Bye")
myMap: scala.collection.immutable.Map[Int,java.lang.String] = Map((1,Hi), (2,Bye))

scala> val jmap = new java.util.HashMap[Int,String](myMap)  // Need explicit types
jmap: java.util.HashMap[Int,String] = {1=Hi, 2=Bye}

Недостатки здесь в том, что у вас уже есть карта Scala (немного расточительная, если вы просто собираетесь создать Java-вариант), и что вам нужно указать типы. Но он компактный и безболезненный.

Метод второй:. Кроме того, вы можете создать новый блок кода в качестве оператора объявления, поэтому вам даже не нужно иметь JavaConversions:

scala> val jmap2 = {              
     |   val x = new java.util.HashMap[Int,String]  
     |   for ((k,v) <- List(1->"Howdy",2->"partner")) x.put(k,v)
     |   x
     | }
jmap2: java.util.HashMap[Int,String] = {1=Howdy, 2=partner}

Чуть менее компактный, но полностью общий, а также эффективный (или неэффективный), как вы его делаете.

Метод третий:. Кроме того, вы можете создать анонимный подкласс HashMap, если он будет иметь подкласс (т.е. .getClass не вернет java.util.HashMap)), и используйте инициализатор для установки ваших значений:

scala> val jmap3 = new java.util.HashMap[Int,String] { 
     |   put(1,"Yo"); put(2,"bro")
     | }
jmap3: java.util.HashMap[Int,String] = {1=Yo, 2=bro}

scala> jmap3.getClass.getName
res0: java.lang.String = $anon$1

scala> jmap3.getClass.getSuperclass.getName
res1: java.lang.String = java.util.HashMap

Недостатком, конечно же, является подкласс HashMap, а не HashMap, но он более компактный, чем версия с назначением-из-кода, поскольку вам не нужно назначать новую карту a val.

Метод четыре: И, наконец, вы можете создать метод, который сделает то, что вы хотите, и назовите его:

scala> def newJHM[A,B](kv: Iterable[(A,B)]) = {
     |   val jhm = new java.util.HashMap[A,B]  
     |   kv.foreach(i => jhm.put(i._1,i._2))   
     |   jhm                                   
     | }                                       
newJHM: [A,B](kv: Iterable[(A, B)])java.util.HashMap[A,B]

scala> val jmap4 = newJHM(Seq(1->"Bye",2->"Now"))  // Type inference now works
jmap4: java.util.HashMap[Int,java.lang.String] = {1=Bye, 2=Now}

Это едва менее компактно, чем другие, и правильные типы, без необходимости указывать их, поэтому это может быть привлекательным выбором, если вы делаете это более одного раза.

P.S. Просто для удовольствия я показал множество способов получить некоторые пары "ключ-значение" на карте, но они не специфичны для данного метода (кроме # 1, для которого требуется карта). Смешайте и согласитесь по своему усмотрению.

Ответ 2

Вы можете сделать карту как анонимный класс и выполнить инициализацию как часть инициализации экземпляра объекта.

import java.util.HashMap
val jhm = new HashMap[String, Int](){
   put(key1, value1)
   put(key2, value2)
}

Это действительно одинаково хорошо работает на Java (за исключением требуемых двойных фигурных скобок {{}}), но гораздо более идиоматично в Scala.

Ответ 3

На основе ответа Randall вы можете использовать JavaConversions, чтобы немного помочь.

import collection.JavaConversions.asMap
import java.util.HashMap
val jhm = new HashMap[Int,String](Map(1->"one", 2->"two"))

Ответ 4

Все методы и конструкторы java.util.HashMap доступны вам, конечно, но это не дает возможности инициализировать карту, если у вас нет другой, чтобы указать начальные значения. Ближе всего вы, вероятно, получите:

import java.util.HashMap
val jhm = new HashMap[String, Int]
«code to add key-value pairs to jhm»

Ответ 5

Чтобы сделать что-то многоразовое, можно было бы создать новый подтип "Карта" только для синтаксиса инициализации.

Он может работать примерно так (я игнорирую generics, потому что я не использую их регулярно, и я, вероятно, ошибаюсь):

HashMap hm=new HashMap(
    new InitMap(
        new String[]{"one", "two", "three"},
        new int[]   {  1  ,   2  ,    3   };
    )
);

В классе InitMap было бы больше кода, но оно было бы многоразовым и довольно прямолинейным (мне очень нравится синтаксис инициализации массива для такого рода материалов).

Размышляя об этом, класс InitMap не будет слишком сложным. Вероятно, вы захотите выяснить, какие методы были вызваны и как их реализовать. Скорее всего, это вызовет только методы KeySet и EntrySet.

Конечно, с такой скоростью вы могли бы просто создать вспомогательный метод, который взял два массива и вернул HashMap или расширил HashMap и добавил новый конструктор...