Reputation: 7083
I find myself using the Scala map function on Option values as follows:
optionVal.map( val => {
doSomethingWith(val)
doSomethingElseWith(val)
// etc. (an example could be executing a database query)
})
where optionVal could be for instance:
Option[String]
In other words, I am using it as a way to ensure that the Option is populated with something, and if so to execute a block of statements.
It seems a bit odd and convoluted to me coming from the Java world where would just do an if check on the object (if (someObject != null) { // execute statements}
). Also it seem like it may not be semantically what the map function was intended to do, even though it works. So I wanted to check if this is the proper / idiomatic way to do this in Scala.
Upvotes: 0
Views: 250
Reputation: 4028
@LimbSoup's answer is definitely appropriate for a case where you're simply calling a side-effectful function with no return type. For the sake of completeness, here are few other ways to work with Option values in Scala. When working with functions that return a value, you've correctly identified one of the more idiomatic methods, using the map
function:
val optX : Option[Int] = Some(1)
optX map { _ + 1 } // returns Some[Int](2)
val optY : Option[Int] = None
optY map { _ + 1 } // returns None
This behavior extends to other functions like filter
and fold
. As syntactic sugar, you can also use a for
comprehension, the same way you would on a list.
for (x <- optX) yield (x + 1) // desugars to 'optX.map(_ + 1)'
for (x <- optX) doSomething(x) // desugars to 'optX.foreach(x => doSomething(x))'
If you want to use Options a bit more in the vein of how you would in Java, you would typically write a pattern matching statement, as follows:
optX match {
case Some(x) => doSomething(x)
case None => doSomethingElse()
}
This is good for when you want an if/else sort of behavior, rather than executing or not executing a function based on whether or not you have a value.
When working with a sequence of Options, you can strip out the None
values by using flatMap
.
// Applies a map to only the types with values
Seq(Some(1), Some(2), Some(3), None, None, None, Some(4)) flatMap { _ + 1 } // returns Seq(2, 3, 4, 5)
Lastly, you can completely throw caution to the wind and call .get
on your Option type. You probably shouldn't, but it's available to you. This will either return the unwrapped value, in case of a 'Some', or throw an exception in case of 'None'.
Upvotes: 0
Reputation: 55569
If doSomethingwith(value)
returns Unit
, then you can use foreach
:
def doSomethingWith(value: Int): Unit = println(value)
val opt: Option[Int] = Some(1)
opt.foreach{ value =>
doSomethingWith(value) // prints the value
}
val noOpt: Option[Int] = None
noOpt.foreach{ value =>
doSomethingWith(value) // Does nothing, because noOpt is empty.
}
If you intend to map (to return it in some way) the value inside the Option
, then continue using map
.
Mapping an Option
to Unit
is harmless, but it would make your code more readable to use foreach
.
Upvotes: 6