问题
I have some Scala code that needs to call a Java API
The Java API takes arguments that may be null. My Scala, of course, uses Option
.
For example, let's say I have a Java object constructor Foo(Integer)
where the Integer
may be null
. I want to call it given a Scala bar: Option[Int]
.
I tried this
import scala.collection.JavaConversions._
import scala.collection.JavaConverters._
val foo = Foo( bar.getOrElse(null) )
But got this compile error
Error:(335, 44) type mismatch;
found : Any
required: Integer
bar.getOrElse(null),
What is the correct idiom for doing this?
回答1:
You don't need a Java method to reproduce this problem:
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))
^
The problem is that Int
can't be null
, so the type of bar.getOrElse(null)
is Any
.
scala> bar.getOrElse(null)
res0: Any = 5
scala> bar.orNull
<console>:15: error: Cannot prove that Null <:< Int.
bar.orNull
^
So you've got to convert the Option
's type parameter to something that can be null
before you unwrap it in a nullable way.
Quickest way I can think of immediately:
scala> new Foo(bar.map(x => x: java.lang.Integer).orNull)
res18: Foo = Foo@cdc45e
Edit: Here, I thought of a more general way to do it!
implicit class RichOption[A](o: Option[A]) {
def toRef[B >: Null](implicit f: A => B): B = o.map(f).orNull
}
Now you can write new Foo(bar.toRef)
:)
回答2:
No sooner do I post the question, than I spot the answer in the related list (sorry)
Here's a solution
val foo = Foo(bar.getOrElse(null).asInstanceOf[java.lang.Integer])
Kind of clunky. Anyone have anything better?
回答3:
More chatter:
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
Of course it's better to
scala> x.fold(null: Integer)(i => i: Integer)
res2: Integer = 42
and even better
scala> x.fold[Integer](null)(identity)
res3: Integer = 42
scala> y.fold[Integer](null)(identity)
res4: Integer = null
来源:https://stackoverflow.com/questions/27611133/calling-java-api-from-scala-with-null-argument