Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

For 4 or fewer elements, something like this works (or at least compiles):

import scala.collection.immutable.Map;

Map<String,String> HAI_MAP = new Map4<>("Hello", "World",
                                        "Happy", "Birthday",
                                        "Merry", "XMas",
                                        "Bye", "For Now");

For a 5th element I could do this:

Map<String,String> b = HAI_MAP.$plus(new Tuple2<>("Later", "Aligator"));

But I want to know how to initialize an immutable map with 5 or more elements and I'm flailing in Type-hell.

Partial Solution

I thought I'd figure this out quickly by compiling what I wanted in Scala, then decompiling the resultant class files. Here's the scala:

object JavaMapTest {
  def main(args: Array[String]) = {
    val HAI_MAP = Map(("Hello", "World"),
                      ("Happy", "Birthday"),
                      ("Merry", "XMas"),
                      ("Bye", "For Now"),
                      ("Later", "Aligator"))
    println("My map is: " + HAI_MAP)
  }
}

But the decompiler gave me something that has two periods in a row and thus won't compile (I don't think this is valid Java):

scala.collection.immutable.Map HAI_MAP =
        (scala.collection.immutable.Map) 
        scala.Predef..MODULE$.Map().apply(scala.Predef..MODULE$.wrapRefArray(
                scala.Predef.wrapRefArray(
                        (Object[])new Tuple2[] {
                                new Tuple2("Hello", "World"),
                                new Tuple2("Happy", "Birthday"),
                                new Tuple2("Merry", "XMas"),
                                new Tuple2("Bye", "For Now"),
                                new Tuple2("Later", "Aligator") }));

I'm really baffled by the two periods in this:

scala.Predef..MODULE$

I asked about it on #java on Freenode and they said the .. looked like a decompiler bug. It doesn't seem to want to compile, so I think they are probably right. I'm running into it when I try to browse interfaces in IntelliJ and am just generally lost.

Based on my experimentation, the following is valid:

Tuple2[] x = new Tuple2[] { new Tuple2<String,String>("Hello", "World"),
                            new Tuple2<String,String>("Happy", "Birthday"),
                            new Tuple2<String,String>("Merry", "XMas"),
                            new Tuple2<String,String>("Bye", "For Now"),
                            new Tuple2<String,String>("Later", "Aligator") };

scala.collection.mutable.WrappedArray<Tuple2> y = scala.Predef.wrapRefArray(x);

There is even a WrappedArray.toMap() method but the types of the signature are complicated and I'm running into the double-period problem there too when I try to research the interfaces from Java.

share|improve this question
    
WHy don't you just create a "regular" map and then copy that map? I guess scala's immutable map has such a constructor? –  fge Jun 29 '13 at 0:26
    
@fge Good thought. There is a MapBuilder, but you have to pass an empty collection, and then the signature of the "add-all" method is complicated: scala.collection.generic.Growable<scala.Tuple2<A,B>> $plus$plus$eq(scala.collection.TraversableOnce<scala.Tuple2<A,B>> xs). I could figure out how to make a Growable and TraversableOnce and call a method named $plus$plus$eq from Java, which IntelliJ did NOT like. Maybe I'll try that route again, but it seemed to me that there must be an easier way. –  GlenPeterson Jun 29 '13 at 0:56
    
Did you look at scala.collection.JavaConversions.mapAsScalaMap ? scala-lang.org/api/current/… –  Reuben Jun 29 '13 at 2:36
    
@Ruben - another good thought, but I'm specifically looking for an immutable collection and JavaConversions try to be true to the Java and use mutable collections. –  GlenPeterson Jul 1 '13 at 19:45
add comment

migrated from stackoverflow.com Jul 2 '13 at 20:08

This question came from our site for professional and enthusiast programmers.

2 Answers

up vote 3 down vote accepted

The decompiler probably has problems in decompiling class names correctly that contain a $ symbol. The symbol you are searching for is named Predef$:

import scala.Predef;
import scala.Predef$;
import scala.Tuple2;
import scala.collection.immutable.Map;
import scala.collection.mutable.WrappedArray;

public class T {
  @SuppressWarnings({ "rawtypes", "unchecked" })
  public static void main(final String... args) {
    final Tuple2[] ts = { new Tuple2("a", "b") };
    final WrappedArray wa = Predef.wrapRefArray(ts);
    final Map<String, String> map = Predef$.MODULE$.Map().apply(wa);
    System.out.println(map);
  }
}

Thus, I emphasize not to use a decompiler but the internal representation of the AST in scalac:

$ scala -print -e 'Map(("a", "b"))'
...
scala.this.Predef.Map().apply(
  scala.this.Predef.wrapRefArray(
    Array[Tuple2]{new Tuple2("a", "b")}.$asInstanceOf[Array[Object]]()));
...

If you are interested in more information about how to work with the output of scalac then take a look at this question and its answers.

share|improve this answer
add comment

How about this?

java.util.Map<String, String> javaMap = new java.util.HashMap<String, String>();
javaMap.put("Hello", "World");
javaMap.put("Happy", "Birthday");
javaMap.put("Merry", "XMas");
javaMap.put("Bye", "For Now");
javaMap.put("Later", "Aligator");

scala.collection.Map<String, String> scalaMap = scala.collection.JavaConversions$.MODULE$.asMap(javaMap);
System.out.println(scalaMap);
share|improve this answer
    
Maybe I'm not reading this correctly, but I think the resultant map is mutable in your example, no? I'm specifically looking for an immutable map. –  GlenPeterson Jul 1 '13 at 19:19
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.