Black Rock Blog

Option.get: The Shortcut That Comes Back to Bite You | BKS2

Option.get: The Shortcut That Comes Back to Bite You

When you know that your Option reference is valid, Option.get will let you quickly access the wrapped value:

1
2
3
def findById(id: String): Option[UserRecord]
...
val currentUserRecord = findById( userId ).get

That was easy! Option.get removes the Option wrapper and returns the inner value so you can get to work with it.

Well, until you starting seeing these stack traces in production:

java.util.NoSuchElementException: None.get
    at scala.None$.get(Option.scala:274)
    ...

Everything was fine when your method was returning the expected Some wrapper in development… unit tests… staging… and production. But then came an unexpected condition when None was returned and your code wasn’t expecting it. None.get will instead throw the above exception, probably in a place where you weren’t expecting to catch one.

Recommendation: Always use Option.getOrElse instead of Option.get

Use Option.getOrElse to provide a default value or behavior when your reference is empty.

  • If your reference is defined, getOrElse returns the unwrapped value
  • If your reference is empty, getOrElse returns the result of your function literal or default value

For example:

1
2
3
def findById(id: String): Option[UserRecord]
...
val currentUserRecord = findById( userId ).getOrElse( defaultUserRecord )

By providing a workaround for empty references, you are making your application sturdier and emphasizing how it handles unexpected conditions. Future maintainers of your code (and you should always plan for them) will thank you.

Note: your function literal is not actually required to return a valid default value here. In cases where an exception is more appropriate there would not actually be anything returned:

1
2
3
4
5
def findById(id: String): Option[UserRecord]
...
val currentUserRecord = findById( userId ).getOrElse {
throw new InvalidUserException(s"Whoah! User '${userId}' couldn't be found!")
}