The prerequisite is that you are familiar with standard assignment and arithmetic operators. If not, read the official Groovy documentation first.
Ternary Operator ? x : y
This operator is a shortcut to writing the following:
if (product.label != null && product.label.length() > 0) { return product.label } else { return 'N/A' }
You can rewrite this using the ternary operator:
return (product.label != null && product.label.length() > 0) ? product.label : 'N/A'
Or even simplify it:
return product.label ? product.label : 'N/A'
Elvis Operator ?:
This operator is a very useful shortcut to writing this:
return product.label ? product.label : 'N/A' // ternary operator return product.label ?: 'N/A' // Elvis operator
You can rewrite it like this:
date = api.targetDate() ?: new Date() // if target date is null, we use the current date
Or:
lookback = api.decimalUserEntry('Look-back period (default: 20)') ?: 20 // if the user doesn't specify the look-back period, it will default to 20
In case you wonder why this is called Elvis operator...
?: → rotate 90° right → →
Safe Navigation Operator ?.
When you check for a null reference every time you want to access object's attribute or method, you might be using something like:
if (date) { return date.format('yyyy-MM-dd') } return null
Advanced Groovy allows you to use the ternary operator:
return date ? date.format('yyyy-MM-dd') : null
But even better is to use the Safe navigation operator:
return date?.format('yyyy-MM-dd')
If the date is null, the whole expression will evaluate to null. You can even chain the calls:
return product?.attribute21?.toBigDecimal()
Spread Operator *
Sometimes you may want to pass a collection of objects to a method which accepts a variable name of parameters only. Such as Filter.or:
def filters = [ Filter.equal('attribute5', 'P'), Filter.equal('attribute5', 'M'), Filter.equal('attribute5', 'U'), ] // this will throw a compilation error as Filter.or doesn't accept a collection but a variable number of Filter arguments api.find('P', Filter.or(filters))
What you need to do is to use the simple * operator to spread the collection of Filters over the Filter.or method.
def filters = [ Filter.equal('attribute5', 'P'), Filter.equal('attribute5', 'M'), Filter.equal('attribute5', 'U'), ] // notice the * char. This will unwrap each element of the collection and pass it to the method as a separate parameter api.find('P', Filter.or(*filters))
Spaceship Operator <=>
This operator delegates to the compareTo
method of the left-side operand and passes it the right-side operand.
assert (1 <=> 1) == 0 assert (1 <=> 2) == -1 assert (2 <=> 1) == 1 assert ('a' <=> 'z') == -1
It is best when mixed with a sort
method.
def competitors = api.productExtension('Competition') def sortedByName = competitors .sort { a, b -> return a.attribute1 <=> b.attribute1 } // assuming attribute1 is the name of the competitor