Groovy Null-Safe Operators
last modified October 15, 2026
Null references are a common source of NullPointerException in Java.
Groovy offers operators that let you navigate through possibly empty values
without writing nested if checks. This tutorial covers the safe
navigation operator ?., the Elvis operator ?:, and the
spread operator *..
Safe Navigation Operator
The safe navigation operator ?. calls a method or accesses a
property only when the object on the left is not null. If the
object is null, the whole expression evaluates to null.
class Address { String city }
class Person { String name; Address address }
def p1 = new Person(name: "Alice", address: new Address(city: "Paris"))
def p2 = new Person(name: "Bob", address: null)
def p3 = null
println p1?.address?.city
println p2?.address?.city
println p3?.name
println p2?.name?.toUpperCase()
p2.address is null, so p2?.address?.city
stops at the first null and returns null instead of
throwing an exception. The same applies to p3 and to the method
call toUpperCase() on a null name.
Elvis Operator
The Elvis operator ?: returns the value on its left when that value
is true in the Groovy sense, and the value on its right otherwise. Since
null, empty strings, and empty collections are false in Groovy, it is
a compact way to supply defaults.
class Address { String city }
class Person { String name; Address address }
def p2 = new Person(name: "Bob", address: null)
def city = p2.address?.city ?: "Unknown"
println city
def name = "" ?: "Anonymous"
println name
When p2.address is null, the expression
p2.address?.city is null too, so the Elvis operator
supplies "Unknown". Combining the two operators is the usual pattern
for optional nested data, such as a user profile read from JSON.
Spread Operator
The spread operator *. applies a property access or method call to
every element of a collection and returns a new list. It is shorthand for
collect, and it also handles null elements safely when
combined with ?..
class Address { String city }
class Person { String name; Address address }
def people = [
new Person(name: "Alice", address: new Address(city: "Paris")),
new Person(name: "Bob", address: null)
]
println people*.name
println people*.address*.city
println people.collect { it?.address?.city }
people*.name produces [Alice, Bob]. The second line
produces [Paris, null], because a null address fails
the navigation for that element only. Using ?. inside a
collect closure gives the same result with more explicit control.
Null-Safe Method Calls on Lists
Calling a method on a null list throws an exception. Guard it with
?. and supply an empty list with ?: when you want
safe iteration.
def findTags(List tags) {
(tags ?: []).findAll { it.startsWith("g") }
}
println findTags(["groovy", "java", "gradle"])
println findTags(null)
def maybe = null
println maybe?.size() ?: 0
Passing null to findTags returns an empty list rather
than failing. The last line shows the common idiom of combining
?. with ?: to get a default count.
Best Practices
- Use ?. for optional data: Apply it where
nullis a legitimate value, such as optional fields in a configuration map. - Do not hide bugs: Overusing
?.can mask missing data that should be an error. Validate required inputs explicitly. - Pair with ?: for defaults: Keep the default value next to the lookup so the intent is clear.
- Prefer spread for lists:
list*.nameis shorter thanlist.collect { it.name }for simple property access.
Source
Groovy Operators Documentation
Null-safe operators let you write chained access that reads naturally while
still handling missing values. Together, ?., ?:, and
*. cover most of the null checks that Java code needs.
Author
List all Groovy tutorials.