Using `Set` Argument to Scala Code in Java

2019-09-22 08:05发布

问题:

I'm trying to call my Scala Util object from Java code:

Main.java

Set<Long> items = new HashSet<Long>();
// fill up items with Long
MyUtil.foo(100, items);

Util.scala

object Foo {
 type Id = Long
 def foo(id: Id, items: scala.collection.mutable.Set[Id]) 

Here's the compile-time error:

  could not parse error message:   
  required: long,scala.collection.mutable.Set<Object>
  found: Long,java.util.Set<Long>
  reason: actual argument java.util.Set<Long> cannot be converted to 
      scala.collection.mutable.Set<Object> by method invocation conversion`

From reading these Java to Scala Collections docs, I am using a mutable Set rather than the default, immutable Set:

scala.collection.mutable.Set <=> java.util.Set

But, I don't understand the error message. By using a Long (boxed long) in my Java code, why is a Set<Long> found?

回答1:

Demonstrating what the commenter said:

scala> import collection.JavaConverters._
import collection.JavaConverters._

scala> val js = (1 to 10).toSet.asJava
js: java.util.Set[Int] = [5, 10, 1, 6, 9, 2, 7, 3, 8, 4]

scala> def f(is: collection.mutable.Set[Int]) = is.size
f: (is: scala.collection.mutable.Set[Int])Int

scala> def g(js: java.util.Set[Int]) = f(js.asScala)
g: (js: java.util.Set[Int])Int

scala> g(js)
res0: Int = 10


回答2:

Working with Scala collections and type aliases from Java code (not the converse, as som-snytt showed :) is going to be at least nasty, most likely very painful, and quite possibly impossible.

If you're able to modify the Scala side of the API, I'd recommend adding a Java-friendlier API to it. If not, I guess you could build an adapter layer in Scala that proxies Java clients through to the native Scala API.

So, something like:

// Original Scala
object Foo {
  type Id = Long
  def foo(id: Id, items: scala.collection.mutable.Set[Id]) 
}

// Java adapter -- generics might be made to work on the Java side, 
// but Long is particularly problematic, so we'll just force it here
object FooJ {
  import scala.collection.JavaConverters._

  def foo(id: Long, items: java.util.Set[Long]) = {
    Foo.foo(id, items.asScala)
  }
}


标签: java scala