# Loop Performance in Groovy

### Learn more about measuring loop performance in Groovy.

Join the DZone community and get the full member experience.

Join For FreeIn the 2018 Advent of Code challenged, I solved all the puzzles in Groovy. It is pretty obvious that choosing a good data structure is the most important part of obtaining a performant solution. However, the way we iterate over those structures is also very significant, at least when using Groovy.

## Measuring Performance

I want to measure how long it takes to sum some numbers. For the performance testing of loops, I prepared a small function that simply sums some numbers:

```
void printAddingTime(String message, long to, Closure<Long> adder) {
LocalTime start = LocalTime.now()
long sum = adder(to)
println("$message: $sum calculated in ${Duration.between(start, LocalTime.now()).toMillis()} ms")
}
```

Pseudo code for summing functions is below:

```
for i = 1 to n
for j = 1 to n
sum += i * j
end
end
```

## Loop Types

Let's implement the summing function in various ways.

`collect`

and `sum`

First, the loop type is to use built-in (by Groovy) function `collect`

and `sum`

on collections (`Range`

it this example):

```
(1..n).collect { long i ->
(1..n).collect { long j ->
i * j
}.sum()
}.sum()
```

`each`

Next, let's write the same function using the `each`

built-in function on collections (`Range`

it this example) and then add results to accumulator variable:

```
long sum = 0
(1..n).each { long i ->
(1..n).each { long j ->
sum += i * j
}
}
return sum
```

`times`

Now, instead of using `each`

, we could use the function `times`

built-in on `Number`

by Groovy:

```
long sum = 0
n.times { long i ->
n.times { long j ->
sum += (i + 1)*(j+1)
}
}
return sum
```

We have to add `1`

to `i`

and `j`

because times generates numbers from `0`

to `n`

exclusive.

`LongStream`

With `sum`

Java 8 came with a new feature — streams. One example of streams is `LongStream`

. Fortunately, it has a`sum`

built-in function, which we can use:

```
LongStream.range(0, n).map { i ->
LongStream.range(0, n).map { j ->
(i + 1) * (j + 1)
}.sum()
}.sum()
```

`LongStream`

generates numbers in the same way as `times`

function, so we also have to add `1`

to `i`

and `j`

here.

`LongStream`

With Manual Sum

Instead of `sum`

function on `LongStream`

, we can add all numbers manually:

```
long sum = 0
LongStream.range(0, n).forEach { i ->
LongStream.range(0, n).forEach { j ->
sum += (i + 1) * (j + 1)
}
}
return sum
```

`while`

Of course, since Groovy inherits a big part of its syntax from Java, we can use the `while`

loop:

```
long sum = 0
long i = 1
while(i <= n){
long j = 1
while(j <= n){
sum+= i*j
++j
}
++i
}
return sum
```

`for`

As we can use `while`

, we can also use `for`

loop in Groovy:

```
long sum = 0
for (long i = 1; i <= n; ++i) {
for (long j = 1; j <= n; ++j) {
sum += i * j
}
}
return sum
```

## Results

For my tests, I ran on Java `1.8`

and Groovy `2.5.5`

. Script `loops.groovy`

was fired using bash script:

```
#!/bin/sh
for x in 10 100 1000 10000 100000; do
echo $x
groovy loops.groovy $x
echo
done
```

Values are in milliseconds:

Loop n | 10 | 100 | 1000 | 10000 | 100000 |
---|---|---|---|---|---|

`collect` + `sum` |
7 | 22 | 216 | 16244 | 1546822 |

`each` |
12 | 17 | 118 | 7332 | 706781 |

`times` |
2 | 10 | 109 | 8264 | 708684 |

`LongStream` + `sum` |
7 | 17 | 127 | 7679 | 763341 |

`LongStream` + manual sum |
18 | 35 | 149 | 6857 | 680804 |

`while` |
8 | 20 | 103 | 3166 | 301967 |

`for` |
7 | 10 | 25 | 359 | 27966 |

As you can spot, although the small number of iterations using built-in Groovy functions is good enough, for a much bigger amount of iterations, we should use `while`

or `for`

loops as in plain, old Java.

Code for these examples is available here. You can run those examples on your machine and check performance on your own.

Happy looping!

Published at DZone with permission of Dominik Przybysz. See the original article here.

Opinions expressed by DZone contributors are their own.

Comments