Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

In this example, the closure block { e -> e.salary > threshold } refers to the threshold variable defined in the highPaid() method. The example also used a closure to create the emps list.

Simulate Javascript-style variable arguments

Groovy supports varargs as Closure parameter, but that requires the use of a Object[] and the closure code has to access the varargs as an Array. 

In JavaScript, function arguments are fully dynamic and you could call a function with any number of arguments different from the number of arguments defined in a function, e.g.

Code Block
javascript
javascript

//javascript
function doSomething( var0, var1){
 alert( 'var0: ' + var0 + ', var1: ' + var1);
}

doSomething( 'value0', 'value1', 'value2' ); //one argument more than in the defined function

If your closure defined more argument than closure call, then you could use:

Code Block

def doSomething = {var0, var1 = null -> }

doSomething( 'value0' )

doSomething( 'value0' , 'value1')

However, you can't do the job exactly like a JavaScript function when your closure has defined less argument than the closure call. If you are the implementer of the closure, you could use varargs (as described in the Formal Guide) to allow your closure to take more arguments than it is defined, and you have to access the extra variables as an Object[].

There are cases you may want to take more arguments but not using varargs/Object[]. For example, as an API provider, you expose an API that take a closure as argument. The closure may define one or two parameters up to the user. (this is a typical case when passing JavaScript function) The following is an example about how to simulate such behaivior:

Code Block

// sample entity
class User{
 def username, password, version, salt = 'RANDOM';
}

// your API, provide a Map of changes to update a entity. the map value may be static value, or a closure that take zero to 2 params
def update( entity, Map changes ){  
 changes?.each {k, v ->
  def newValue;
  if (v instanceof Closure){
   switch (v.parameterTypes.length) {
    case 0: newValue = v(); break;
    case 1: newValue = v(entity[k]); break; // if one params, the closure is called with the field value
    case 2: newValue = v(entity[k],entity); break; // if two params, the closure is called with teh field value and the entity
   }
  }else{
   newValue = v
  }
  entity[k] = newValue
 }
}

// user code
def user1 = new User(username:'user1', password:'pass1', version:0)
update( user1, [password:{v,e-> Hash.md5(v, e.salt) }, version:{v-> v+1 }]

Other Examples

  • You could define a closure that take a closure as argument, and combine the use of other Groovy techniques to do a lot of things. See the Closure, Category and JPA example

...