Whenever
null
seems like a good idea, useOption
instead.
As far as types are concerned, null
is a bit of a lie:
val s: String = null
The compiler believes s
to be a String
and will accept it wherever one is required. The compiler is, obviously, wrong:
s.toLowerCase
// java.lang.NullPointerException
// at repl.Session$App$$anonfun$2.apply(avoid_null.md:15)
// at repl.Session$App$$anonfun$2.apply(avoid_null.md:15)
Whenever you’re using null
, you’re hindering the compiler’s ability to prove your code incorrect.
The existence of null
is terribly unpleasant: it means that you can’t trust any value to not be null
. So, in theory, you’d be forced to write code like:
def concat(a: String, b: String): String = {
if(a == null) b
else if(b == null) a
else s"$a$b"
}
That’s a lot of boilerplate. In Scala, the general convention is that we pretend null
does not exist and any value not wrapped in an Option
must always be available. This allows us to rewrite concat
:
def concat(a: String, b: String): String = s"$a$b"
Just as importantly, if we were to write concat
such that either a
or b
might not be set, the compiler forces us to deal with this:
def concat(a: Option[String], b: Option[String]): String =
s"${a.getOrElse("")}${b.getOrElse("")}"
There exists at least one scenario in which you must use null
: Java interop. Java being what it is, some of its APIs use null
to mean no value there, and you don’t have much choice but to comply.
The standard URI
class, for example, expect null
values in its constructor - if you don’t have a fragment, say, stick null
instead and URI
will work it out.
Linter | Rule |
---|---|
Scalastyle | |
Scapegoat |
|
WartRemover |