Whenever
nullseems like a good idea, useOptioninstead.
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 |