This blog post “Harnessing the power of groovy” demonstrates the power of groovy language. In java, what could take 10-15 lines, in groovy we can achieve it using 1-line code.

Multiply Each Number by 2

(1..10).collect{it * 2}

Adding numbers in a list

(1..1000).sum()

new File("jft.txt").text

Filtering a list

def (groupA, groupB) = [30, 50, 55, 65, 85, 95].split{it > 60}

Find Min/Max in a List

[10, 20, 30, 80, 100].min()

The above tips were quite basic and easy to understand. I would also like to introduce some advanced concepts of groovy: memoization and trampolining.

What is Trampolining ?

It is used in case of recursive closures. It is used to avoid StackOverflow exception which occurs when there are many return values stored on the stack.

def factorial
factorial = {
it <= 1 ? 1 : it * factorial(it - 1)
}
factorial(500) //stack overflow exception

Now, let’s try the trampolined version:

def factorial
factorial = {it, acc = 1->
it <= 1 ? acc : factorial.trampoline(it - 1, it * acc)
}.trampoline()

factorial(500) //no stack overflow

In the above example there is no stack overflow exception. The trampoline method wraps our closure into a TrampolineClosure object and groovy executes factorial.trampoline(..) calls sequentially until our closure returns something else than an instance of TrampolineClosure. So, the stack is not filled up and does not result in StackOverflow exception. It is called “tail call optimization”.

What is Memoization ?

Memoization is a technique that is used to store the results of function calls and returning the cached result when the same input occurs. It results in faster processing.

It can be very useful for recursive calculations like calculating factorial, Fibonacci using recursion.

Here is an example to demonstrate it:

Non-Memoized version

fib =  { f ->
println "Fibonacci for number: \$f"
if (f <= 1) {
return f
}
fib(f - 1) + fib(f - 2)
}

fib(5)

Output:

Fibonacci for 5
Fibonacci for 4
Fibonacci for 3
Fibonacci for 2
Fibonacci for 1
Fibonacci for 0
Fibonacci for 1
Fibonacci for 2
Fibonacci for 1
Fibonacci for 0
Fibonacci for 3
Fibonacci for 2
Fibonacci for 1
Fibonacci for 0
Fibonacci for 1 We can see many duplicate calls for values like 1,2,3 etc. in the above example.

Now let’s try a memoized version:

fib =  { f ->
println "Fibonacci for number: \$f"
if (f <= 1) {
return f
}
fib(f - 1) + fib(f - 2)
}.memoize()

fib(5)

Output:

Fibonacci for number: 5
Fibonacci for number: 4
Fibonacci for number: 3
Fibonacci for number: 2
Fibonacci for number: 1
Fibonacci for number: 0 We can now see in the above example that there is not even a single duplicate call which really saves a lot of time.

If you try fib(45) or fib(50) without memoization it will take more than 30 seconds to give the output.

That was all 🙂