I have this Java class in a Jar file included as a dependency of an Scala program (like the Axis jar):
class MyClass {
private String[] someStrings;
public String[] getSomeStrings() { return someStrings; }
}
In my Scala program I have a Java API that return an instance of MyClass instance of MyClass to my program in Scala:
val myInstance = JavaAPI.getInstanceOfMyClass()
Then I try to use the someStrings array in my Scala program but it's null (let say that it wasn't properly initialized)
for(str <- myInstance.getSomeStrings()) ...
So this throws a NullPointerException.
I've found that in order to use it in the for comprehension I can wrap it into an Option so that it handles the NPE properly.
for(str <- Option[Array[String]](myInstance.getSomeStrings).getOrElse(Array[String]())
But that doesn't look OK to me.
Is there a way to create like an implicit method that takes that value even if it's null and wrap it into the Option, like:
implicit def wrapNull(a: Null): Option[Nothing] = None
implicit def wrapArray(a: Array[String]): Option[Array[String]] = Some(a)
So that when I do:
for(str <- myInstance.getSomeStrings())
I don't get the NPE
edit:
A map
as well as a flatMap
always have to return the same type, on which they are called. If you have a List, you will always get a List back from map
. The same is true for an Option. If you try to mix 2 types in a flatMap, this will most likely not work. What should
Some(Array(1,2)).flatMap { x =>
x.map { _ * 2 }
}
return? Some(2,4) is not possible. So you get a type error. For this reason you have to do a nested map { map }
instead of flatMap { map }
.
In your case it would work like this:
case class A(b: B)
case class B(c: String)
val result = for(as <- Option(Array(A(B("foo")), A(B("bar"))))) yield {
for(a <- as; b <- Option(a.b); c <- Option(b.c)) yield {
c
}
}
The first for
takes an Option[Array[A]]
and returns an Option[Array[String]]
. The nested for takes an Array[A]
and returns an Array[String]
. They both satisfy the monad laws. At the end you can safely call getOrElse
on result
to unwrap the value if you want to.
original:
You could just do
val result = Option(myInstance.getSomeStrings).map { x =>
x.map { y =>
// do stuff with strings
}
}
or
val result = for(x <- Option(myInstance.getSomeStrings)) yield {
x.map { y =>
// do stuff with strings
}
}
You don't need to write the types because of the type inference and you don't need getOrElse
, because the map will not be executed for None
. You can then simply do a getOrElse
on result, if you need to unwrap the value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With