How do I create an empty immutable Scala map in Java?

冷暖自知 提交于 2019-12-10 12:46:42

问题


This should be an obvious one but I've not yet found an elegant solution. For various reasons, I need to create an immutable Scala map (scala.collection.immutable.Map from Scala 2.10), but I can only write Java code. How do I do this?


回答1:


Wild guess - here goes nothing:

scala.collection.immutable.Map$.MODULE$.<…, …>empty()



回答2:


At first I was puzzled that just doing the following would fail:

scala.collection.immutable.Map<Integer, String> = scala.collection.immutable.Map$.<Integer, String>empty();

The reason it seemed odd is because I know for a fact that scala generates static forwarders that internally dereference MODULE$ and call the corresponding (non-static) method. I made some tests, and although what I found is somewhat tangential to the original question, it is still related and good to know.

Say we have the following:

package test
object MyScalaObject {
  def empty[A, B]: Map[A, B] = sys.error("TODO")
}

Using javap we can see that a static forwarder is generated:

public class test.MyScalaObject extends java.lang.Object{
    public static scala.collection.immutable.Map empty();
    public test.MyScalaObject();
}

And indeed we can in java just do the following:

scala.collection.immutable.Map<Integer, String> myMap = test.MyScalaObject.<Integer, String>empty();

All is well and nice. However, if we add a class or trait MyScalaObject that also defines a method with the same signature, no static forwarder is generated by scala (certainly because the JVM does not allow a class to define both a static and non-static method with the same signature). There are probably other different subtle situations that prevent the static forwarders to be generated.

Consider:

package test
class MyScalaObject {
  def empty[A, B]: Map[A, B] = sys.error("TODO")
}
object MyScalaObject {
  def empty[A, B]: Map[A, B] = sys.error("TODO TOO")
}

javap shows that the static forwarder has indeed disappeared:

public class test.MyScalaObject extends java.lang.Object{
    public scala.collection.immutable.Map empty();
    public test.MyScalaObject();
}

In this case it means that we have to explictly dereference $MODULE which points to the (unique) instance of the singleton object:

scala.collection.immutable.Map<Integer, String> myMap = test.MyScalaObject$.MODULE$.<Integer, String>empty();

As it turns out, both the trait scala.collection.immutable.Map and its companion object define a parameterless empty method, so we stumble upon this very issue.

The moral is that while static forwarders are a potentially useful feature, it is also very fragile because the mere fact of modifying a class (in this case adding an empty method in class MyScalaObject) can break the feature, without even touching its companion object itself. It is thus certainly a good idea to always explicitly reference MODULE$ (as in Wilfred Springer's answer) even if it looks less nice and even if the static forwarder is currently present, to prevent potential breakage when updating to a newer version of the library.



来源:https://stackoverflow.com/questions/14365048/how-do-i-create-an-empty-immutable-scala-map-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!