I want to this code snippet return me None instead of Some(null):
Option(x).map(x.getNullValue) // returns Some(null)
I heard Scalaz library has features to handle such case. So how I can achieve my goal using both: scalaz and standard Scala library?
You could use flatMap together with the Option.apply method here instead of pulling in scalaz:
Option(initialValue).flatMap(x => Option(x.getNullValue))
This works since the Option.apply method treads null intelligently:
val x: String = null
Option(x) //None
Option("foo") //Some("foo")
So if you know the value outright, you can simply do:
Option(x.getNullValue)
You can also use other methods on Option like filter, orElse, or getOrElse, depending on the situation:
Option(initialValue).map(_.getNullValue).filter(_ != null)
Option(initialValue).orElse(Option(x.getNullValue))
Option(x.getNullValue).getOrElse(defaultValue)
I don't know about scalaz, but in the standard library your only choice really is to filter out the null value. map simply maps A => B and expects that B will not be null.
Example:
object HasNull {
def getNull: Any = null
}
scala> Option(HasNull).map(_.getNull).filter(_ != null)
res24: Option[Any] = None
Or
scala> Option(HasNull).flatMap(a => Option(a.getNull))
res25: Option[Any] = None
Alternatively, you can use a little implicit magic to avoid the Option boilerplate:
implicit def toOpt[A](a: A): Option[A] = Option(a)
scala> Option(HasNull).flatMap(_.getNull)
res3: Option[Any] = None
Using flatMap still is the key, because it expects an Option[B]. But getNull is of type B, so the implicit conversion will be used, which will wrap the nullable in Option.apply again.
As others already wrote, you can do it using flatMap. And a very similar approach is:
case class User(name: String)
val users = List(null, User("John"), User(null))
for{
userDb <- users
user <- Option(userDb)
name <- Option(user.name)
} yield name
The problem with None is that you do not know which None you get: user doesn't exist or name? In this case scalaz can help you:
for{
userDb <- users
user <- Option(userDb) \/> "No user found."
name <- Option(user.name) \/> "No name provided."
} yield name
But this is another story. You can find awesome explanation about this use case here (video).
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