Friday, October 19, 2018

Navigate safely with null-safe operator for Maps in Groovy . . .

It is not overstating to say that, NullPointerException (known as NPE), in Java is annoying and dreaded. ;) So much of noisy if conditional check code-blocks get added to main logic simply as a way to avoid it safely. Missing these safety if checks will result into run-time NullPointerException indicating a bug. Java doesn't provide any elegant syntax to deal with annoyance.

Groovy offered null-safe operator ( ?. ) right from the beginning. Recent JVM languages started offering ways to deal with it safely with which Java developers are falling in love. But, what Groovy offers with null-safe operator ( ?. ), is the most elegant syntax for safely navigating an object graph.

Groovy also offers consistent way of referring element in a collection with subscript operator ( [] ). The subscript operator is a short-hand notation for groovy's added getAt() method for collections in addition to Java provided get() method. Accessing elements of Arrays, Lists, Sets and Maps is consistent with subscript operator.

This safe navigation operator can't be used with collections to access elements safely with subscript notation. For instance, myList[0] to get first element from the list throws NPE when myList variable itself is null. Whereas, directly using the underlying Groovy provided method, myList?.getAt(0) is safer way to access first element without causing dreaded NPE. Java provided get(n) also can be used safely with ?. only for Arrays and Lists, but beware that it throws run-time IndexOutOfBoundsException if subscript index goes beyond the size, where Groovy's getAt(n) returns null in this case.

However, for Maps, Groovy offers additional notation (property notation) to reference key to get it's value. Unlike, subscript notation, this additional notation offers null-safety.

Environment: Groovy 2.4.15Java 8 on MacOS High Sierra 10.13.6

Example code

Map nullMap = null // calling getAt() method is null-safe anyway, as it is groovy's way of safely navigating object graph assert nullMap?.getAt('name') == null /* * Notation-1: Subscript notation * - Null-unsafe way of referencing key * - Throws NullPointerException */ try { assert nullMap['name'] == null // key literal } catch(NullPointerException npe) { assert npe.message == "Cannot get property 'name' on null object" } String key = 'name' try { assert nullMap[(key)] == null // when value of variable is the key } catch(NullPointerException npe) { assert npe.message == "Cannot get property 'name' on null object" } /* * Notation-2: Property notation * Null-safe way of referencing key * Doesn't throw NullPointerException */ assert nullMap?.name == null // key literal assert nullMap?."$key" == null // when value of variable is the key

Summary

So, for Maps, there are 3 options, where String ABCD is the key:
  • Subscript notation ( myMap['ABCD'] ) - can't use null-safe operator and hence can get NPE
  • Use underlying method directly ( myMap?.getAt('ABCD') ) - can use null-safe operator but is verbose
  • Property notation ( myMap?.ABCD) - can use null-safe operator and is more readable.
I got into this trap by using subscript operator ( [] ) few times in the past, and hence sharing it in this post.

4 comments:

  1. See also safe map indexing in Groovy 3 (currently in alpha):

    http://groovy-lang.org/releasenotes/groovy-3.0.html#_safe_indexing

    ReplyDelete
  2. That's one of the features I would love to have. Thanks for sharing. Looking forward to it's release.

    ReplyDelete
  3. Thank you!!! However, for list like def a =[1,2,3], we cannot use a?[0] or a?.0 ,right? only a?.get(0) ? any idea?

    ReplyDelete
    Replies
    1. Thank you! With groovy 3, a?[0] is possible. Check the link in the other comment.

      Delete