27

I'm using some Scala library from my Java code. And I have a problem with collections. I need to pass scala.collection.immutable.Map as a parameter of a method. I can convert or build immutable.Map from my Java code but I do not know how to do it. Suggestions?

7 Answers 7

24

It's entirely possible to use JavaConverters in Java code—there are just a couple of additional hoops to jump through:

import java.util.HashMap;
import scala.Predef;
import scala.Tuple2;
import scala.collection.JavaConverters;
import scala.collection.immutable.Map;

public class ToScalaExample {
  public static <A, B> Map<A, B> toScalaMap(HashMap<A, B> m) {
    return JavaConverters.mapAsScalaMapConverter(m).asScala().toMap(
      Predef.<Tuple2<A, B>>conforms()
    );
  }

  public static HashMap<String, String> example() {
    HashMap<String, String> m = new HashMap<String, String>();
    m.put("a", "A");
    m.put("b", "B");
    m.put("c", "C");
    return m;
  }
}

We can show that this works from the Scala REPL:

scala> val jm: java.util.HashMap[String, String] = ToScalaExample.example
jm: java.util.HashMap[String,String] = {b=B, c=C, a=A}

scala> val sm: Map[String, String] = ToScalaExample.toScalaMap(jm)
sm: Map[String,String] = Map(b -> B, c -> C, a -> A)

But of course you could just as easily call these methods from Java code.

Sign up to request clarification or add additional context in comments.

2 Comments

There is no "toMap" method any more. The code above can't be compiled for Java 1.7 and Scala 2.11 :(
jdk 1.8, it shows "can't access scala.Predef.$less$colon$less" error
5

My solution for Java 1.7 and Scala 2.11:

@SuppressWarnings("unchecked")
private static <K, V> scala.collection.immutable.Map<K, V> toScalaImmutableMap(java.util.Map<K, V> javaMap) {
    final java.util.List<scala.Tuple2<K, V>> list = new java.util.ArrayList<>(javaMap.size());
    for (final java.util.Map.Entry<K, V> entry : javaMap.entrySet()) {
        list.add(scala.Tuple2.apply(entry.getKey(), entry.getValue()));
    }
    final scala.collection.Seq<Tuple2<K, V>> seq = scala.collection.JavaConverters.asScalaBufferConverter(list).asScala().toSeq();
    return (scala.collection.immutable.Map<K, V>) scala.collection.immutable.Map$.MODULE$.apply(seq);
}

Comments

5

Since I couldn't make it with Alexey's answer, I'll add that in Scala 2.13 it can be done using:

scala.collection.immutable.Map<Integer, String> scalaMap =
        scala.collection.immutable.Map.from(scala.jdk.CollectionConverters.MapHasAsScala(javaMap).asScala());

Comments

4

This worked for me with java 1.8 and scala 2.12:

public static <K, V> scala.collection.immutable.Map<K, V> toScalaImmutableMap(java.util.Map<K, V> jmap) {
    List<Tuple2<K, V>> tuples = jmap.entrySet()
      .stream()
      .map(e -> Tuple2.apply(e.getKey(), e.getValue()))
      .collect(Collectors.toList());
    
    Seq<Tuple2<K, V>> scalaSeq = JavaConverters.asScalaBuffer(tuples).toSeq();
    
    return (Map<K, V>) Map$.MODULE$.apply(scalaSeq);
}

Comments

3

Since Scala 2.13 you can use CollectionConverters to achieve that.

Having

Map<String, String> javaMap = ...

First we convert it to mutable Scala map:

import scala.jdk.javaapi.CollectionConverters$;

var mutableScalaMap = CollectionConverters$.MODULE$.asScala(javaMap);

And then to immutable one:

var scalaMap = scala.collection.immutable.Map$.MODULE$.from(mutableScalaMap);

Comments

0

Can you provide an additional API call that takes/provides a java.util.Map converted using JavaConverters ?

class Example {
   import scala.collection.JavaConverters._
   def fromMap(m:Map[...]) = ...

   // generics etc. elided
   def fromJava(m:java.util.Map) = {
      fromMap(m.asScala.toMap)
   }
}

You may wish to extract the conversion and provide a decorator (especially as I note you're working to a Scala library). Note dhg's comment re. immutability.

1 Comment

Yes. Hence my opening question - 'Can you provide an additional API call that takes/provides a java.util.Map'
-2

Simply use toMap (Scala 2.12)

import scala.collection.JavaConverters._

// asScala creates mutable Scala Map
// toMap after asScala creates immutable Map

val scalaImmutableMap = javaMap.asScala.toMap

2 Comments

HI @TomerShetah I might be wrong ,but to convert Java to Scala collection , we should be writing the convertor in scala.
But the question asks for java code, which this is not. So it does not answer the question, regardless if you are right or wrong.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.