Scala: How to parse a number from a String

This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 2.1, “Parsing a Number from a String.”

Problem

You want to convert a String to one of Scala’s numeric types (Byte, Double, Int, Float, Long, Short).

Solution

Use the to* methods that are available on a String (courtesy of the StringLike trait):

scala> "100".toInt
res0: Int = 100

scala> "100".toDouble
res1: Double = 100.0

scala> "100".toFloat
res2: Float = 100.0

scala> "1".toLong
res3: Long = 1

scala> "1".toShort
res4: Short = 1

scala> "1".toByte
res5: Byte = 1

Be careful because these methods can throw the usual Java NumberFormatException:

scala> "foo".toInt
java.lang.NumberFormatException: For input string: "foo"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
    at java.lang.Integer.parseInt(Integer.java:449)
    ... more output here ...

BigInt and BigDecimal instances can also be created directly from strings (and can also throw a NumberFormatException):

scala> val b = BigInt("1")
b: scala.math.BigInt = 1

scala> val b = BigDecimal("3.14159")
b: scala.math.BigDecimal = 3.14159

Handling a base and radix

If you need to perform calculations using bases other than 10, you’ll find the toInt method in the Scala Int class doesn’t have a method that lets you pass in a base and radix. To solve this problem, use the parseInt method in the java.lang.Integer class, as shown in these examples:

scala> Integer.parseInt("1", 2)
res0: Int = 1

scala> Integer.parseInt("10", 2)
res1: Int = 2

scala> Integer.parseInt("100", 2)
res2: Int = 4

scala> Integer.parseInt("1", 8)
res3: Int = 1

scala> Integer.parseInt("10", 8)
res4: Int = 8

If you’re a fan of implicit conversions, you can create an implicit class and method to help solve the problem. As described in Recipe 1.11, “Add Your Own Methods to the String Class,” create the implicit conversion as follows:

implicit class StringToInt(s: String) {
    def toInt(radix: Int) = Integer.parseInt(s, radix)
}

Defining this implicit class (and bringing it into scope) adds a toInt method that takes a radix argument to the String class, which you can now call instead of calling Integer.parseInt:

scala> implicit class StringToInt(s: String) {
     |   def toInt(radix: Int) = Integer.parseInt(s, radix)
     | }
defined class StringToInt

scala> "1".toInt(2)
res0: Int = 1

scala> "10".toInt(2)
res1: Int = 2

scala> "100".toInt(2)
res2: Int = 4

scala> "100".toInt(8)
res3: Int = 64

scala> "100".toInt(16)
res4: Int = 256

See Recipe 1.11 for more details on how to implement this solution outside of the REPL.

Discussion

If you’ve used Java to convert a String to a numeric data type, the NumberFormatException is familiar. However, Scala doesn’t have checked exceptions, so you’ll probably want to handle this situation differently.

First, you don’t have to declare that Scala methods can throw an exception, so it’s perfectly legal to declare a Scala method like this:

// not required to declare "throws NumberFormatException"
def toInt(s: String) = s.toInt

If you’re going to allow an exception to be thrown like this, callers of your method might appreciate knowing that this can happen. Consider adding a Scaladoc comment to your method in this case.

If you prefer to declare that your method can throw an exception, mark it with the @throws annotation, as shown here:

@throws(classOf[NumberFormatException])
def toInt(s: String) = s.toInt

This approach is required if the method will be called from Java code, as described in Recipe 19.2., “Add Exception Annotations to Scala Methods to Work with Java.” However, in Scala, situations like this are often handled with the “Option/Some/None” pattern, as described in Recipe 20.6. With this approach, define the toInt method like this:

def toInt(s: String):Option[Int] = {
    try {
        Some(s.toInt)
    } catch {
        case e: NumberFormatException => None
    }
}

or this:

import scala.util.control.Exception._
def makeInt(s: String): Option[Int] = allCatch.opt(s.toInt)

Now you can call the toInt method in several different ways, depending on your needs. The preferred approach is to use a match expression. You can write a match expression to print the toInt result like this:

toInt(aString) match {
    case Some(n) => println(n)
    case None => println("Boom! That wasn't a number.")
}

You can also write it as follows to assign the result to a variable:

val result = toInt(aString) match {
    case Some(x) => x
    case None => 0  // however you want to handle this
}

If these examples haven’t yet sold you on the Option/Some/None approach, you’ll see in the Collections chapter that this pattern is incredibly helpful and convenient when working with collections.

You can also use getOrElse:

println(toInt("1").getOrElse(0))   // 1
println(toInt("a").getOrElse(0))   // 0

// assign the result to x
val x = toInt(aString).getOrElse(0)

Alternatives to Scala’s Option

If you like the Option/Some/None concept, but need access to the exception information, there are several additional possibilities:

  • Try, Success, and Failure (introduced in Scala 2.10)
  • Either, Left, and Right

Here are examples of how to use allCatch in Scala with the Option, Try, and Either classes:

import scala.util.control.Exception._
import scala.util.{Try, Success, Failure}

// Option
def toInt(s: String): Option[Int] = allCatch.opt(Integer.parseInt(s))

// Try
def toInt(s: String): Try[Int] = allCatch.withTry(Integer.parseInt(s))

// Either
def toInt(s: String): Either[Throwable, Int] = allCatch.either(Integer.parseInt(s))

See Also