How can I concisely set a default value for a value of a closure that is not populated?
Below I thought using the optional chaining operator would prevent throwing an exception, but I still got an exception.
myfunction {
FOO="myfoo"
BAZ="mybaz"
}
def myfunction(Closure body = {}) {
body()
foo = body?.FOO ?: "defaultFoo"
// getting exception since BAR isnt defined
bar = body?.BAR ?: "defaultBar"
println("foo=" + foo + " bar=" + bar)
}
You can solve it by setting a dedicated Binding
on your closure with a map that returns a default value (e.g. null
) for non-existing keys.
myfunction {
FOO="myfoo"
BAZ="mybaz"
}
def myfunction(Closure body = {}) {
def binding = new Binding([:].withDefault {}) // <1>
body.setBinding(binding) // <2>
body()
foo = binding.FOO // <3>
bar = binding.BAR
println("foo=" + foo + " bar=" + bar)
}
Output:
foo=myfoo bar=null
There are three critical changes to your code.
new Binding([:].withDefault {})
object, where [:].withDefault {}
is a map that returns a value defined inside the closure for any key that does not exist. In our case, we use an empty closure to return null
value, but if we do e.g. [:].withDefault { 1 }
, then we create a map that returns 1
for non-existing keys.body.setBinding(binding)
to make use of this custom Binding
instance.binding
object, not the body
closure.