Home > Back-end >  Handle java.lang.NullPointerException in scala when accessing nested fields
Handle java.lang.NullPointerException in scala when accessing nested fields

Time:07-17

I have a use case where

    name = Person.getFirstSister().getname()

Person.getSister().getname() gives java.lang.NullPointerException since Person.getSister() is java null

What is the right way to do this in scala. I am able to achieve with below code. But looking for more scala way of doing it.

  private def getFirstSisterName(person: Person): String = {
    val sister = person.getFirstSister()
    if (sister == null) ""
    else sister.getName()
  }

CodePudding user response:

Checking for null is the Java way to go. Scala offers a much more streamlined set of operations to avoid doing null checks manually.

Naturally, getSister should result in an Option[Sister], the argument being that not every person has a sister.

Going on the same idea, trying to mimic the real word, I would ask: but what if a person has multiple sisters? How do you distinguish between them? This implies your design is not very general because it implies every person has a sister.

So the idiomatic way is to have the method return a List[Sisters]. Then map their names from the list. If the list is empty, Nil, the empty list will be the result, so we won't have any NPE:

  case class Sister(name: String)
  case class Person(sisters: List[Sister]) {
    def sistersNames: String = sisters.map(_.name).mkString(" ")
  }

  val p = Person(List(Sister("Sandra"), Sister("Joanna")))
  val p2 = Person(List.empty)

  println(p.sistersNames)    // Sandra Joanna
  println(p2.sistersNames)   // empty String

EDIT:

If you can't change Person or Sister, the alternative is to make your wrapper method to treat the null case. You can do this in 2 ways, either use pattern matching, or wrap the result in an Option. Note: Option(x) checks if the code is null and if it is, it converts it to a None. That is why applying fold works.

  private def getFirstSisterName(person: Person): String =
    person.getFirstSister match {
      case s: Sister => s.name
      case _         => s"${person.toString} does not have a sister"
    }

  private def getFirstSisterName2(person: Person): String = {
    val sis = Option(person.getFirstSister)
    sis.fold(s"${person.toString} does not have a sister")(_.name)
  }

  val p = new Person(new Sister("Sandra"))
  val p2 = new Person(null)

  println(getFirstSisterName(p))     // Sandra
  println(getFirstSisterName2(p))    // Sandra
  println(getFirstSisterName(p2))    // person827966648 does not have a sister
  println(getFirstSisterName2(p2))   // person827966648 does not have a sister
  • Related