如何在Java中创建一个空的不可变Scala映射?

2022-09-04 19:38:55

这应该是一个显而易见的问题,但我还没有找到一个优雅的解决方案。由于各种原因,我需要创建一个不可变的Scala映射(Scala.collection.immutable.Map from Scala 2.10),但我只能编写Java代码。我该怎么做?


答案 1

疯狂的猜测 - 这里什么都没有:

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

答案 2

起初我很困惑,仅仅做以下事情就会失败:

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

它看起来很奇怪的原因是因为我知道一个事实,scala会生成静态转发器,这些转发器会在内部取消引用并调用相应的(非静态)方法。我做了一些测试,虽然我发现的东西与原来的问题有些纠缠,但它仍然是相关的,很高兴知道。MODULE$

假设我们有以下内容:

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

使用我们可以看到生成了一个静态转发器:javap

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

事实上,我们可以在java中执行以下操作:

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

一切都很好,很好。但是,如果我们添加一个类或特征,该类或特征也定义了具有相同签名的方法,则scala不会生成静态转发器(当然,因为JVM不允许类定义具有相同签名的静态和非静态方法)。可能还有其他不同的微妙情况阻止生成静态转发器。MyScalaObject

考虑:

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表明静态转发器确实消失了:

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

在这种情况下,这意味着我们必须明确地取消引用指向单例对象的(唯一)实例:$MODULE

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

事实证明,trait及其伴随对象都定义了一个无参数方法,因此我们偶然发现了这个问题。scala.collection.immutable.Mapempty

寓意是,虽然静态转发器是一个潜在的有用功能,但它也非常脆弱,因为仅仅修改一个类(在这种情况下,在类中添加一个方法)的事实就可以破坏该功能,甚至不需要触及它的伴随对象本身。因此,始终显式引用(如Wilfred Springer的答案)当然是一个好主意,即使它看起来不太好,即使当前存在静态转发器,以防止在更新到较新版本的库时潜在的中断。emptyMyScalaObjectMODULE$