How to handle null input in Scala

I know that in Scala a method should never return null ... but what about the input parameters? Given the following piece of code ...

 object MyObject { def myMethod(p: String): Option[String] = { if (p == null) throw new IllegalArgumentException("p is null.") ... } } 

... so am I checking p correctly? Are there any recommendations?

+8
scala
source share
4 answers

The convention is that Scala code does not use NULL values ​​(with a few exceptions that should be fixed immediately when using these library functions).

So zero from Scala is a sign that something went wrong (at least PBCAK ), so you can also throw an exception, This is not an ordinary operation; it is something serious. Catch the exception wherever you find serious disgust. Capturing IllegalArgumentException instead of NullPointerException does not add additional information. Just leave the original alone.

If the code comes from Java, the canonical way to deal with it is to wrap it in Option , which converts null to None . Then you probably don't even need to throw an exception; just return a None .

 def myMethod(p: String) = Option(p).map(_.toLowerCase) 

If you cannot continue when it is null, you need to think about whether an informative exception will help. Option(p).orElse(throw new IllegalArgumentException("Null!")) Is one compact way to express emotions that create an exception.

In Scala 2.10, you can also wrap things in scala.util.Try(...) , which will automatically catch and pack an exception for you. If you want a packed exception instead of a thrown, this is the way to go. (And use Try instead of Option .)

 import scala.util.Try def myMethod(p: String) = Try(p.toLowerCase) 

Finally, for more general handling of alternative results, use Either . The convention for error handling is that the expected result is Right(whatever) , and Left(whatever) indicates that something went wrong.

+19
source share

There are several ways, and your path is one.

You can also use:

 require(p != null, "p is null.") 

or a β€œmore functional" way is to use Option :

 def myMethod(p: String): Option[String] = { // no exception for { pp <- Option(p) } yield p + " foo bar" } 

edit:

or if you want to get an error without exception, you can use Either :

 def myMethod(p: String): Either[Exception, String] = { if(p == null) Left(new IllegalArgumentException("p is null.")) else Right(p + "foo bar") } 
+6
source share

The Scala idiom is essentially "not using zero values ​​ever." Therefore, if you are not writing an API that should contain dirty Java users, I simply would not worry about that. Otherwise, you will insert this pattern check for each parameter for each method that you write.

Your beautiful single line methods

 def square(x: String): String = math.pow(x.toInt, 2).toInt.toString 

will turn into something uncomfortable like

 def square(x: String): String = if (x == null) throw new NullPointerException() math.pow(x.toInt, 2).toInt.toString } 

or

 def square(x: String): String = Option(x) match { case Some(x) => math.pow(x.toInt, 2).toInt.toString case None => throw new NullPointerException() } 

How awful.

0
source share

My favorite approach is something like:

 object HandlingInputValidation { def main(args: Array[String]) = { println("A1: " + handleInput("Correct ") + " END") println("A2: " + handleInput("Correct") + " END") println("A3: " + handleInput("") + " END") println("A4: " + handleInput(" ") + " END") println("A5: " + handleInput(null) + " END") } def handleInput(data: String): Option[String] = { Option(data).map(_.trim.toLowerCase) } } 

In this case, null will be None , and spaces will be trimmed.

0
source share

All Articles