使用null参数从Scala调用Java API

opu*_*111 6 null scala java-api scala-option

我有一些需要调用Java API的Scala代码

Java API接受可能为null的参数.我的Scala当然使用了Option.

举例来说,假设我有一个Java对象的构造Foo(Integer),其中Integer可能null.我想给Scala打电话bar: Option[Int].

我试过这个

import scala.collection.JavaConversions._
import scala.collection.JavaConverters._

val foo = Foo( bar.getOrElse(null) )
Run Code Online (Sandbox Code Playgroud)

但得到了这个编译错误

Error:(335, 44) type mismatch;
  found   : Any
  required: Integer
  bar.getOrElse(null),
Run Code Online (Sandbox Code Playgroud)

这样做的正确习惯是什么?

Chr*_*tin 5

您不需要Java方法来重现此问题:

scala> import scala.collection.JavaConversions._
import scala.collection.JavaConversions._

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

scala> class Foo(a: java.lang.Integer)
defined class Foo

scala> val bar: Option[Int] = Some(5)
bar: Option[Int] = Some(5)

scala> new Foo(bar.getOrElse(null))
<console>:16: error: type mismatch;
 found   : Any
 required: Integer
              new Foo(bar.getOrElse(null))
                                   ^
Run Code Online (Sandbox Code Playgroud)

问题是Int不可能null,所以类型bar.getOrElse(null)Any.

scala> bar.getOrElse(null)
res0: Any = 5

scala> bar.orNull
<console>:15: error: Cannot prove that Null <:< Int.
              bar.orNull
                  ^
Run Code Online (Sandbox Code Playgroud)

所以你必须将你Option的类型参数转换为可以null在以可空的方式展开之前的类型参数.

我能立刻想到的最快方式:

scala> new Foo(bar.map(x => x: java.lang.Integer).orNull)
res18: Foo = Foo@cdc45e
Run Code Online (Sandbox Code Playgroud)

编辑:在这里,我想到了更通用的方法!

implicit class RichOption[A](o: Option[A]) {
    def toRef[B >: Null](implicit f: A => B): B = o.map(f).orNull
}
Run Code Online (Sandbox Code Playgroud)

现在你可以写new Foo(bar.toRef):)


opu*_*111 3

我一发布问题,就在相关列表中找到答案(抱歉)

这是一个解决方案

val foo = Foo(bar.getOrElse(null).asInstanceOf[java.lang.Integer])
Run Code Online (Sandbox Code Playgroud)

有点笨重。有人有更好的吗?

  • 我对这个解决方案的抱怨是“asInstanceOf”掩盖了类型错误。如果 `bar` 是一个 `Option[String]`,它会编译但抛出 `ClassCastException`。 (4认同)