Reputation: 12900
I am trying to learn the scala, and one thing confuses me is this:
Why following code returns List[Any]
and not List[String]
def listToLowerCase(l: List[String]) = l.map(s=>if(s != null) s.toLowerCase)
is it because when string is null
I am not even call lowerCase
function? but shouldn't it return nothing?
Upvotes: 1
Views: 64
Reputation: 22840
In Scala, most control structures are expressions and not statements.
Thus, the if-else
has to return a value. Since you do not have an else
branch, the compiler inserts this else ()
. So your code returns sometimes Strings other times Unit and the LUB of those two types is Any.
There are a couple of ways to solve this, one is to ensure the list doesn't have nulls
before the map
(in general in Scala we never expect a null
). Other is to return some default value when the string is null
for example and empty string. Another one is to use the Option data type to represent missing values.
Here are some suggestions:
list.filter(_ != null).map(_.toLowerCase)
list.collect { case str if (str != null) => str.toLowerCase }
list.map(str => if (str != null) str.toLowerCase else "")
list.map(str => Option(str).map(_.toLowerCase))
list.map(str => Option(str).map(_.toLowerCase)).getOrElse("")
list.map(str => Option(str).fold(ifEmpty = "")(_.toLowerCase))
list.flatMap(str => Option(str).map(_.toLowerCase))
I would recommend you the last four, as direct manipulation of null
in Scala is not recommended. Except if performance is a must and the allocation of Option
is too expensive for your use case (that is rarely the case).
Upvotes: 3
Reputation: 48410
When else
part of conditional expression is not provided
if(s != null) s.toLowerCase
then by default it expands to
if(s != null) s.toLowerCase else ()
where s.toLowerCase
types to String
whilst ()
types to Unit
, hence the least upper bound of the two is Any
. As per SLS
A short form of the conditional expression eliminates the else-part. The conditional expression
if (𝑒1) 𝑒2
is evaluated as if it wasif (𝑒1) 𝑒2 else ()
.
Note we could filter out null
before lower-casing like so
List[String]("AA", null).flatMap(Option(_)).map(_.toLowerCase)
// res0: List[String] = List(aa)
because Option(null)
is None
.
Upvotes: 1