public abstract class Closure<V> extends GroovyObjectSupport implements Cloneable, Runnable, GroovyCallable<V>, Serializable
Groovy allows instances of Closures to be called in a short form. For example:
def a = 1
def c = { a }
assert c() == 1
To be able to use a Closure in this way with your own
subclass, you need to provide a doCall method with any
signature you want to. This ensures that
getMaximumNumberOfParameters() and
getParameterTypes() will work too without any
additional code. If no doCall method is provided a
closure must be used in its long form like
def a = 1
def c = {a}
assert c.call() == 1
| Modifier and Type | Field and Description |
|---|---|
static int |
DELEGATE_FIRST
With this resolveStrategy set the closure will attempt to resolve property references and methods to the
delegate first then the owner.
|
static int |
DELEGATE_ONLY
With this resolveStrategy set the closure will resolve property references and methods to the delegate
only and entirely bypass the owner.
|
static int |
DONE |
static Closure |
IDENTITY |
protected int |
maximumNumberOfParameters |
static int |
OWNER_FIRST
With this resolveStrategy set the closure will attempt to resolve property references and methods to the
owner first, then the delegate (this is the default strategy).
|
static int |
OWNER_ONLY
With this resolveStrategy set the closure will resolve property references and methods to the owner only
and not call the delegate at all.
|
protected Class[] |
parameterTypes |
static int |
SKIP |
static int |
TO_SELF
With this resolveStrategy set the closure will resolve property references to itself and go
through the usual MetaClass look-up process.
|
| Constructor and Description |
|---|
Closure(Object owner)
Constructor used when the "this" object for the Closure is null.
|
Closure(Object owner,
Object thisObject) |
| Modifier and Type | Method and Description |
|---|---|
Closure |
asWritable() |
V |
call()
Invokes the closure without any parameters, returning any value if applicable.
|
V |
call(Object... args) |
V |
call(Object arguments)
Invokes the closure, returning any value if applicable.
|
Object |
clone() |
Closure<V> |
curry(Object... arguments)
Support for Closure currying.
|
Closure<V> |
curry(Object argument)
Support for Closure currying.
|
Closure<V> |
dehydrate()
Returns a copy of this closure where the "owner", "delegate" and "thisObject"
fields are null, allowing proper serialization when one of them is not serializable.
|
Object |
getDelegate() |
int |
getDirective() |
int |
getMaximumNumberOfParameters() |
Object |
getOwner() |
Class[] |
getParameterTypes() |
Object |
getProperty(String property)
Retrieves a property value.
|
int |
getResolveStrategy()
Gets the strategy which the closure uses to resolve methods and properties
|
Object |
getThisObject() |
boolean |
isCase(Object candidate) |
Closure<V> |
leftShift(Closure other)
Support for Closure reverse composition.
|
V |
leftShift(Object arg)
Alias for calling a Closure for non-closure arguments.
|
Closure<V> |
memoize()
Creates a caching variant of the closure.
|
Closure<V> |
memoizeAtLeast(int protectedCacheSize)
Creates a caching variant of the closure with automatic cache size adjustment and lower limit
on the cache size.
|
Closure<V> |
memoizeAtMost(int maxCacheSize)
Creates a caching variant of the closure with upper limit on the cache size.
|
Closure<V> |
memoizeBetween(int protectedCacheSize,
int maxCacheSize)
Creates a caching variant of the closure with automatic cache size adjustment and lower and upper limits
on the cache size.
|
Closure<V> |
ncurry(int n,
Object... arguments)
Support for Closure currying at a given index.
|
Closure<V> |
ncurry(int n,
Object argument)
Support for Closure currying at a given index.
|
Closure<V> |
rcurry(Object... arguments)
Support for Closure "right" currying.
|
Closure<V> |
rcurry(Object argument)
Support for Closure "right" currying.
|
Closure<V> |
rehydrate(Object delegate,
Object owner,
Object thisObject)
Returns a copy of this closure for which the delegate, owner and thisObject are
replaced with the supplied parameters.
|
<W> Closure<W> |
rightShift(Closure<W> other)
Support for Closure forward composition.
|
void |
run() |
void |
setDelegate(Object delegate)
Allows the delegate to be changed such as when performing markup building
|
void |
setDirective(int directive) |
void |
setProperty(String property,
Object newValue)
Sets the given property to the new value.
|
void |
setResolveStrategy(int resolveStrategy)
Sets the strategy which the closure uses to resolve property references and methods.
|
protected static Object |
throwRuntimeException(Throwable throwable) |
Closure<V> |
trampoline()
Builds a trampolined variant of the current closure.
|
Closure<V> |
trampoline(Object... args)
Builds a trampolined variant of the current closure.
|
getMetaClass, invokeMethod, setMetaClasspublic static final int OWNER_FIRST
class Test {
def x = 30
def y = 40
def run() {
def data = [ x: 10, y: 20 ]
def cl = { y = x + y }
cl.delegate = data
cl()
assert x == 30
assert y == 70
assert data == [x:10, y:20]
}
}
new Test().run()
Will succeed, because the x and y fields declared in the Test class shadow the variables in the delegate.Note that local variables are always looked up first, independently of the resolution strategy.
public static final int DELEGATE_FIRST
class Test {
def x = 30
def y = 40
def run() {
def data = [ x: 10, y: 20 ]
def cl = { y = x + y }
cl.delegate = data
cl.resolveStrategy = Closure.DELEGATE_FIRST
cl()
assert x == 30
assert y == 40
assert data == [x:10, y:30]
}
}
new Test().run()
This will succeed, because the x and y variables declared in the delegate shadow the fields in the owner class.Note that local variables are always looked up first, independently of the resolution strategy.
public static final int OWNER_ONLY
class Test {
def x = 30
def y = 40
def run() {
def data = [ x: 10, y: 20, z: 30 ]
def cl = { y = x + y + z }
cl.delegate = data
cl.resolveStrategy = Closure.OWNER_ONLY
cl()
println x
println y
println data
}
}
new Test().run()
will throw "No such property: z" error because even if the z variable is declared in the delegate, no
lookup is made.Note that local variables are always looked up first, independently of the resolution strategy.
public static final int DELEGATE_ONLY
class Test {
def x = 30
def y = 40
def z = 50
def run() {
def data = [ x: 10, y: 20 ]
def cl = { y = x + y + z }
cl.delegate = data
cl.resolveStrategy = Closure.DELEGATE_ONLY
cl()
println x
println y
println data
}
}
new Test().run()
will throw an error because even if the owner declares a "z" field, the resolution strategy will bypass
lookup in the owner.Note that local variables are always looked up first, independently of the resolution strategy.
public static final int TO_SELF
Note that local variables are always looked up first, independently of the resolution strategy.
public static final int DONE
public static final int SKIP
public static final Closure IDENTITY
protected Class[] parameterTypes
protected int maximumNumberOfParameters
public Closure(Object owner)
owner - the Closure ownerpublic void setResolveStrategy(int resolveStrategy)
resolveStrategy - The resolve strategy to setDELEGATE_FIRST,
DELEGATE_ONLY,
OWNER_FIRST,
OWNER_ONLY,
TO_SELFpublic int getResolveStrategy()
DELEGATE_FIRST,
DELEGATE_ONLY,
OWNER_FIRST,
OWNER_ONLY,
TO_SELFpublic Object getThisObject()
public Object getProperty(String property)
GroovyObjectgetProperty in interface GroovyObjectgetProperty in class GroovyObjectSupportproperty - the name of the property of interestpublic void setProperty(String property, Object newValue)
GroovyObjectsetProperty in interface GroovyObjectsetProperty in class GroovyObjectSupportproperty - the name of the property of interestnewValue - the new value for the propertypublic boolean isCase(Object candidate)
public V call()
public V call(Object arguments)
arguments - could be a single value or a List of valuespublic Object getOwner()
public Object getDelegate()
public void setDelegate(Object delegate)
delegate - the new delegatepublic Class[] getParameterTypes()
public int getMaximumNumberOfParameters()
public Closure asWritable()
Object.toString() in order
to allow rendering the result directly to a String.public Closure<V> curry(Object... arguments)
Typical usage:
def multiply = { a, b -> a * b }
def doubler = multiply.curry(2)
assert doubler(4) == 8
Note: special treatment is given to Closure vararg-style capability.
If you curry a vararg parameter, you don't consume the entire vararg array
but instead the first parameter of the vararg array as the following example shows:
def a = { one, two, Object[] others -> one + two + others.sum() }
assert a.parameterTypes.name == ['java.lang.Object', 'java.lang.Object', '[Ljava.lang.Object;']
assert a(1,2,3,4) == 10
def b = a.curry(1)
assert b.parameterTypes.name == ['java.lang.Object', '[Ljava.lang.Object;']
assert b(2,3,4) == 10
def c = b.curry(2)
assert c.parameterTypes.name == ['[Ljava.lang.Object;']
assert c(3,4) == 10
def d = c.curry(3)
assert d.parameterTypes.name == ['[Ljava.lang.Object;']
assert d(4) == 10
def e = d.curry(4)
assert e.parameterTypes.name == ['[Ljava.lang.Object;']
assert e() == 10
assert e(5) == 15
arguments - the arguments to bindpublic Closure<V> curry(Object argument)
argument - the argument to bindcurry(Object...)public Closure<V> rcurry(Object... arguments)
def divide = { a, b -> a / b }
def halver = divide.rcurry(2)
assert halver(8) == 4
The position of the curried parameters will be calculated lazily, for example,
if two overloaded doCall methods are available, the supplied arguments plus the
curried arguments will be concatenated and the result used for method selection.arguments - the arguments to bindcurry(Object...)public Closure<V> rcurry(Object argument)
argument - the argument to bindrcurry(Object...)public Closure<V> ncurry(int n, Object... arguments)
def caseInsensitive = { a, b -> a.toLowerCase() <=> b.toLowerCase() } as Comparator
def caseSensitive = { a, b -> a <=> b } as Comparator
def animals1 = ['ant', 'dog', 'BEE']
def animals2 = animals1 + ['Cat']
// curry middle param of this utility method:
// Collections#binarySearch(List list, Object key, Comparator c)
def catSearcher = Collections.&binarySearch.ncurry(1, "cat")
[[animals1, animals2], [caseInsensitive, caseSensitive]].combinations().each{ a, c ->
def idx = catSearcher(a.sort(c), c)
print a.sort(c).toString().padRight(22)
if (idx < 0) println "Not found but would belong in position ${-idx - 1}"
else println "Found at index $idx"
}
// =>
// [ant, BEE, dog] Not found but would belong in position 2
// [ant, BEE, Cat, dog] Found at index 2
// [BEE, ant, dog] Not found but would belong in position 2
// [BEE, Cat, ant, dog] Not found but would belong in position 3
The position of the curried parameters will be calculated eagerly
and implies all arguments prior to the specified n index are supplied.
Default parameter values prior to the n index will not be available.n - the index from which to bind parameters (may be -ve in which case it will be normalized)arguments - the arguments to bindcurry(Object...)public Closure<V> ncurry(int n, Object argument)
argument - the argument to bindncurry(int, Object...)public <W> Closure<W> rightShift(Closure<W> other)
Typical usage:
def times2 = { a -> a * 2 }
def add3 = { a -> a + 3 }
def timesThenAdd = times2 >> add3
// equivalent: timesThenAdd = { a -> add3(times2(a)) }
assert timesThenAdd(3) == 9
other - the Closure to compose with the current Closurepublic Closure<V> leftShift(Closure other)
Typical usage:
def times2 = { a -> a * 2 }
def add3 = { a -> a + 3 }
def addThenTimes = times2 << add3
// equivalent: addThenTimes = { a -> times2(add3(a)) }
assert addThenTimes(3) == 12
other - the Closure to compose with the current Closurepublic V leftShift(Object arg)
Typical usage:
def times2 = { a -> a * 2 }
def add3 = { a -> a * 3 }
assert add3 << times2 << 3 == 9
arg - the argument to call the closure withpublic Closure<V> memoize()
public Closure<V> memoizeAtMost(int maxCacheSize)
maxCacheSize - The maximum size the cache can grow topublic Closure<V> memoizeAtLeast(int protectedCacheSize)
protectedCacheSize - Number of cached return values to protect from garbage collectionpublic Closure<V> memoizeBetween(int protectedCacheSize, int maxCacheSize)
protectedCacheSize - Number of cached return values to protect from garbage collectionmaxCacheSize - The maximum size the cache can grow topublic Closure<V> trampoline(Object... args)
def fact
fact = { n, total ->
n == 0 ? total : fact.trampoline(n - 1, n * total)
}.trampoline()
def factorial = { n -> fact(n, 1G)}
println factorial(20) // => 2432902008176640000
args - Parameters to the closure, so as the trampoline mechanism can call itpublic Closure<V> trampoline()
trampoline(Object...)public int getDirective()
public void setDirective(int directive)
directive - The directive to set.public Closure<V> dehydrate()
public Closure<V> rehydrate(Object delegate, Object owner, Object thisObject)
dehydrate()
method.delegate - the closure delegateowner - the closure ownerthisObject - the closure "this" object