【问题标题】:Calling Java API from Scala with null argument使用 null 参数从 Scala 调用 Java API
【发布时间】:2014-12-22 22:05:19
【问题描述】:

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

Java API 接受可能为空的参数。当然,我的 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) )

但是得到了这个编译错误

Error:(335, 44) type mismatch;
  found   : Any
  required: Integer
  bar.getOrElse(null),

这样做的正确成语是什么?

【问题讨论】:

    标签: scala null java scala-option


    【解决方案1】:

    您不需要 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))
                                       ^
    

    问题是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
                      ^
    

    因此,您必须先将Option 的类型参数转换为可以为null 的值,然后才能以可空方式展开它。

    我能立即想到的最快方法:

    scala> new Foo(bar.map(x => x: java.lang.Integer).orNull)
    res18: Foo = Foo@cdc45e
    

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

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

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

    【讨论】:

    • 谢谢你,克里斯。我现在知道了。我想知道是否可以/应该添加一些隐式 JavaConverters 以使调用 Java 更容易,并避免在 Scala 代码中使用 NULL 的诱惑;-)
    • 竖起大拇指,但我会称之为toRefx.toRef[Integer]。 SO nanny 不允许 cmets 中的增量运算符。回到幼儿园感觉很奇怪,椅子这么小。
    【解决方案2】:

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

    解决办法

    val foo = Foo(bar.getOrElse(null).asInstanceOf[java.lang.Integer])
    

    有点笨重。谁有更好的?

    【讨论】:

    • 抱怨我有这个解决方案是asInstanceOf 掩盖了类型错误。如果barOption[String],则编译但会抛出ClassCastException
    【解决方案3】:

    更多闲聊:

    scala> import runtime.BoxesRunTime.boxToInteger
    import runtime.BoxesRunTime.boxToInteger
    
    scala> val x = Some(42)
    x: Some[Int] = Some(42)
    
    scala> val y: Option[Int] = None
    y: Option[Int] = None
    
    scala> x.fold(null: Integer)(boxToInteger)
    res0: Integer = 42
    
    scala> y.fold(null: Integer)(boxToInteger)
    res1: Integer = null
    

    当然更好

    scala> x.fold(null: Integer)(i => i: Integer)
    res2: Integer = 42
    

    甚至更好

    scala> x.fold[Integer](null)(identity)
    res3: Integer = 42
    
    scala> y.fold[Integer](null)(identity)
    res4: Integer = null
    

    【讨论】:

      猜你喜欢
      • 2021-11-26
      • 2017-05-05
      • 1970-01-01
      • 2013-02-13
      • 1970-01-01
      • 2019-02-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多