Learn Groovy times loop with times() with 10 practical examples. Repeat actions N times with clean syntax. Complete guide tested on Groovy 5.x.
“Simplicity is the ultimate sophistication. Why write a for loop when you can just say how many times?”
Alan Kay, Smalltalk Pioneer
Last Updated: March 2026 | Tested on: Groovy 5.x, Java 17+ | Difficulty: Beginner | Reading Time: 14 minutes
Ever written a for loop just to repeat something a fixed number of times and thought, “There must be a cleaner way”? The groovy times loop via the times() method lets you write 5.times { } instead of for (int i = 0; i < 5; i++) – no counter variable, no off-by-one errors, no boilerplate.
Instead of writing for (int i = 0; i < 5; i++), you simply write 5.times { }. That’s it. No counter variable to manage, no off-by-one errors, no boilerplate. It’s one of those Groovy features that makes you wonder why every language doesn’t have it.
In this post, we’ll explore the times() method with 10 practical, tested examples. We’ll also cover the closely related upto(), downto(), and step() methods. If you’re coming from our Groovy for loop or Groovy each loop guides, you’ll see how times() fits into the bigger picture of Groovy iteration.
Table of Contents
What Is the Groovy times() Method?
The times() method is defined on the Integer class by the Groovy Development Kit (GDK). It executes a closure a specified number of times. According to the official Groovy GDK documentation, the method signature is:
times() Method Signature
public void times(Closure closure)
The closure receives an implicit parameter it – the current iteration index starting from 0. So 5.times { } runs the closure 5 times, with it going from 0 to 4.
Key Points:
- Called directly on any
Integervalue - Executes the closure exactly N times
- Index starts at 0, ends at N-1
- Returns
void– it’s purely for side effects - Calling
0.times { }does nothing (no error) - Negative numbers also do nothing (no error)
Syntax and Basic Usage
Basic times() Syntax
// Simplest form - no index needed
3.times {
println "Hello!"
}
// With implicit index (it)
3.times {
println "Iteration: ${it}"
}
// With named parameter
3.times { index ->
println "Step ${index + 1} of 3"
}
Output
Hello! Hello! Hello! Iteration: 0 Iteration: 1 Iteration: 2 Step 1 of 3 Step 2 of 3 Step 3 of 3
Notice the three variations. When you don’t care about the index, just use an empty closure parameter. When you want the index, either use the implicit it or name it explicitly for better readability.
Quick Reference Table
| Method | Range | Description | Example |
|---|---|---|---|
n.times{} | 0 to n-1 | Repeat n times | 5.times { print it } → 01234 |
a.upto(b){} | a to b (inclusive) | Count up from a to b | 1.upto(5) { print it } → 12345 |
b.downto(a){} | b to a (inclusive) | Count down from b to a | 5.downto(1) { print it } → 54321 |
a.step(b,s){} | a to b (exclusive), step s | Count with custom step | 0.step(10,2) { print it } → 02468 |
times() vs for Loop
If you’ve been using Groovy for loops, you might wonder when to use times() instead. Here’s a direct comparison:
times() vs for Loop
// Java-style for loop
println "=== Java-style for ==="
for (int i = 0; i < 5; i++) {
print "${i} "
}
println()
// Groovy range for loop
println "=== Range for ==="
for (i in 0..4) {
print "${i} "
}
println()
// times() - cleanest
println "=== times() ==="
5.times { print "${it} " }
println()
Output
=== Java-style for === 0 1 2 3 4 === Range for === 0 1 2 3 4 === times() === 0 1 2 3 4
All three produce the same result, but times() is the most concise. Use times() when you just need to repeat something N times. Use a for loop when you need break or continue – times() doesn’t support those since it uses a closure. Use each() when you’re iterating over a collection.
10 Practical times() Examples
Example 1: Basic times() – Repeat a Message
What we’re doing: Running a simple action multiple times without caring about the index.
Example 1: Basic times()
// Print a message 5 times
5.times {
println "Groovy is awesome!"
}
Output
Groovy is awesome! Groovy is awesome! Groovy is awesome! Groovy is awesome! Groovy is awesome!
What happened here: The closure runs exactly 5 times. We didn’t use it at all – sometimes you just want to repeat an action without tracking which iteration you’re on. This is the simplest form of the Groovy times loop.
Example 2: times() with the Index Variable (it)
What we’re doing: Using the implicit it parameter to access the iteration index.
Example 2: Using the Index
// Print index values
println "=== Index values ==="
5.times {
println "Index: ${it}"
}
// Use index in calculations
println "\n=== Squares ==="
6.times {
println "${it} squared = ${it * it}"
}
Output
=== Index values === Index: 0 Index: 1 Index: 2 Index: 3 Index: 4 === Squares === 0 squared = 0 1 squared = 1 2 squared = 4 3 squared = 9 4 squared = 16 5 squared = 25
What happened here: The implicit parameter it holds the current iteration index, starting at 0. This is a Groovy closure convention – when a closure has a single parameter you don’t name, it’s automatically called it.
Example 3: times() with a Named Parameter
What we’re doing: Giving the index a meaningful name for better readability.
Example 3: Named Parameter
// Named parameter makes code self-documenting
println "=== Countdown ==="
5.times { count ->
println "T-minus ${5 - count}..."
}
println "Liftoff!"
println "\n=== Player Scores ==="
4.times { playerIndex ->
def score = (playerIndex + 1) * 100
println "Player ${playerIndex + 1}: ${score} points"
}
Output
=== Countdown === T-minus 5... T-minus 4... T-minus 3... T-minus 2... T-minus 1... Liftoff! === Player Scores === Player 1: 100 points Player 2: 200 points Player 3: 300 points Player 4: 400 points
What happened here: Instead of using the generic it, we named the parameter count and playerIndex. This is especially useful when the closure body is more than a line or two – named parameters make the intent crystal clear.
Example 4: Building a Collection with times()
What we’re doing: Using times() to populate a list with generated data.
Example 4: Building Collections
// Build a list of items
def items = []
5.times { items << "Item-${it + 1}" }
println "Items: ${items}"
// Build a list of maps
def users = []
3.times { i ->
users << [id: i + 1, name: "User_${i + 1}", active: true]
}
println "Users: ${users}"
// Build a matrix (list of lists)
def matrix = []
3.times { row ->
def cols = []
3.times { col ->
cols << (row * 3 + col + 1)
}
matrix << cols
}
println "Matrix: ${matrix}"
Output
Items: [Item-1, Item-2, Item-3, Item-4, Item-5] Users: [[id:1, name:User_1, active:true], [id:2, name:User_2, active:true], [id:3, name:User_3, active:true]] Matrix: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
What happened here: Since times() returns void, we can’t use it directly for collection building like collect(). Instead, we declare the collection outside and use the left-shift operator (<<) to append items inside the closure. The nested times() call for the matrix shows you can nest these loops just like nested for loops.
Example 5: Test Data Generation with times()
What we’re doing: Generating test data – one of the most common real-world uses of times().
Example 5: Test Data Generation
def random = new Random(42) // fixed seed for reproducible output
// Generate test users
def testUsers = []
10.times { i ->
testUsers << [
id : i + 1,
username : "testuser_${i + 1}",
email : "user${i + 1}@test.com",
age : 20 + random.nextInt(40),
role : i < 2 ? 'admin' : 'user'
]
}
println "Generated ${testUsers.size()} test users:"
testUsers.each { user ->
println " ${user.id}. ${user.username} (${user.email}) - age: ${user.age}, role: ${user.role}"
}
Output
Generated 10 test users: 1. testuser_1 (user1@test.com) - age: 30, role: admin 2. testuser_2 (user2@test.com) - age: 23, role: admin 3. testuser_3 (user3@test.com) - age: 28, role: user 4. testuser_4 (user4@test.com) - age: 24, role: user 5. testuser_5 (user5@test.com) - age: 30, role: user 6. testuser_6 (user6@test.com) - age: 25, role: user 7. testuser_7 (user7@test.com) - age: 45,
What happened here: We used 10.times to generate a batch of test user maps. The index i drives the unique IDs, usernames, and email addresses. The first two users get the admin role while the rest are regular users. This pattern is incredibly common in unit tests and Spock specifications.
Example 6: Retry Logic with times()
What we’re doing: Implementing a simple retry mechanism – another practical use case for times().
Example 6: Retry Logic
// Simulate a flaky operation that fails sometimes
def random = new Random(42)
def success = false
def maxRetries = 5
maxRetries.times { attempt ->
if (!success) {
println "Attempt ${attempt + 1} of ${maxRetries}..."
// Simulate: 40% chance of success
if (random.nextInt(100) < 40) {
println " ✓ Operation succeeded on attempt ${attempt + 1}!"
success = true
} else {
println " ✗ Failed. ${attempt < maxRetries - 1 ? 'Retrying...' : 'No more retries.'}"
}
}
}
if (!success) {
println "All ${maxRetries} attempts failed."
}
Output
Attempt 1 of 5... ✓ Operation succeeded on attempt 1!
What happened here: We used times() to cap the maximum number of retry attempts. Since times() doesn’t support break, we used a success flag to skip the remaining iterations once the operation passes. In production code, you’d typically add a Thread.sleep() between retries for backoff.
Example 7: upto() – Count Up Between Two Numbers
What we’re doing: Using upto() to iterate from a starting number to an ending number (both inclusive).
Example 7: upto()
// Count from 1 to 5
print "1 to 5: "
1.upto(5) { print "${it} " }
println()
// Multiplication table for 7
println "\n7 times table:"
1.upto(10) { num ->
println " 7 x ${num} = ${7 * num}"
}
// ASCII characters from A to Z
print "\nAlphabet: "
65.upto(90) { print "${(char)it}" }
println()
Output
1 to 5: 1 2 3 4 5 7 times table: 7 x 1 = 7 7 x 2 = 14 7 x 3 = 21 7 x 4 = 28 7 x 5 = 35 7 x 6 = 42 7 x 7 = 49 7 x 8 = 56 7 x 9 = 63 7 x 10 = 70 Alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZ
What happened here: Unlike times() which always starts at 0, upto() lets you specify both the start and end values. Both endpoints are inclusive, so 1.upto(5) gives you 1, 2, 3, 4, 5. This is often cleaner than times() when your logic is 1-based rather than 0-based.
Example 8: downto() – Count Down
What we’re doing: Using downto() to iterate in reverse – from a higher number to a lower one.
Example 8: downto()
// Simple countdown
print "Countdown: "
10.downto(1) { print "${it} " }
println("Go!")
// Reverse a number range
println "\nFloor selector (top to ground):"
5.downto(0) { floor ->
def label = floor == 0 ? "Ground" : "Floor ${floor}"
println " → ${label}"
}
// Decreasing powers of 2
println "\nPowers of 2 (descending):"
10.downto(0) { exp ->
println " 2^${exp} = ${Math.pow(2, exp).intValue()}"
}
Output
Countdown: 10 9 8 7 6 5 4 3 2 1 Go! Floor selector (top to ground): → Floor 5 → Floor 4 → Floor 3 → Floor 2 → Floor 1 → Ground Powers of 2 (descending): 2^10 = 1024 2^9 = 512 2^8 = 256 2^7 = 128 2^6 = 64 2^5 = 32 2^4 = 16 2^3 = 8 2^2 = 4 2^1 = 2 2^0 = 1
What happened here: downto() is the mirror image of upto(). It iterates from the calling integer down to the argument, both inclusive. This is much cleaner than writing for (i = 10; i >= 1; i--).
Example 9: step() – Custom Step Size
What we’re doing: Using step() to iterate with a custom increment (or decrement).
Example 9: step()
// Even numbers from 0 to 20
print "Evens: "
0.step(21, 2) { print "${it} " }
println()
// Count by 5s
print "By 5s: "
0.step(51, 5) { print "${it} " }
println()
// Step backwards
print "Reverse by 3: "
30.step(-1, -3) { print "${it} " }
println()
// Step through hours of the day
println "\nWork hours:"
9.step(18, 1) { hour ->
def period = hour < 12 ? "AM" : "PM"
def displayHour = hour > 12 ? hour - 12 : hour
println " ${displayHour}:00 ${period}"
}
Output
Evens: 0 2 4 6 8 10 12 14 16 18 20 By 5s: 0 5 10 15 20 25 30 35 40 45 50 Reverse by 3: 30 27 24 21 18 15 12 9 6 3 0 Work hours: 9:00 AM 10:00 AM 11:00 AM 12:00 PM 1:00 PM 2:00 PM 3:00 PM 4:00 PM 5:00 PM
What happened here: The step() method takes two parameters: the end value (exclusive) and the step size. A positive step counts up, a negative step counts down. Notice that the end value is exclusive – unlike upto() and downto() which are inclusive.
Example 10: Combining times() with Other Methods
What we’re doing: Using times() alongside other Groovy collection methods for more complex tasks.
Example 10: Combining Methods
// Build and process a list
def scores = []
10.times { scores << new Random(it).nextInt(100) }
println "Scores: ${scores}"
println "Average: ${scores.sum() / scores.size()}"
println "Max: ${scores.max()}, Min: ${scores.min()}"
// Create a formatted table
println "\n+------+--------+--------+"
println "| Num | Square | Cube |"
println "+------+--------+--------+"
8.times { n ->
def num = n + 1
printf "| %4d | %6d | %6d |\n", num, num * num, num * num * num
}
println "+------+--------+--------+"
// String repetition vs times()
def separator = "-" * 40
println "\n${separator}"
println " times() can do what '*' can't:"
println separator
3.times { i ->
println " ${' ' * (i * 2)}Level ${i}"
}
Output
Scores: [60, 85, 10, 68, 74, 99, 24, 42, 57, 31]
Average: 55.0
Max: 99, Min: 10
+------+--------+--------+
| Num | Square | Cube |
+------+--------+--------+
| 1 | 1 | 1 |
| 2 | 4 | 8 |
| 3 | 9 | 27 |
| 4 | 16 | 64 |
| 5 | 25 | 125 |
| 6 | 36 | 216 |
| 7 | 49 | 343 |
| 8 | 64 | 512 |
+------+--------+--------+
----------------------------------------
times() can do what '*' can't:
----------------------------------------
Level 0
Level 1
Level 2
What happened here: We combined times() with collection methods like sum(), max(), and min(). We also used printf for formatted output and the string multiplication operator ("x" * n) alongside times(). The string * operator repeats a string, while times() repeats an action – they complement each other well.
Related Methods: upto(), downto(), and step()
We saw upto(), downto(), and step() in the examples above. Let’s do a quick side-by-side comparison to lock in when to use each one:
Comparison: All Four Methods
// times() - repeat N times, 0-indexed
print "times: "
5.times { print "${it} " }
println()
// upto() - inclusive range going up
print "upto: "
1.upto(5) { print "${it} " }
println()
// downto() - inclusive range going down
print "downto: "
5.downto(1) { print "${it} " }
println()
// step() - custom step, exclusive end
print "step: "
0.step(10, 2) { print "${it} " }
println()
Output
times: 0 1 2 3 4 upto: 1 2 3 4 5 downto: 5 4 3 2 1 step: 0 2 4 6 8
When to use which:
- times() – When you just need to repeat something N times and the 0-based index is fine.
- upto() – When you want a specific start and end (1-based ranges, counting from X to Y).
- downto() – When you need to count backwards (countdowns, reverse processing).
- step() – When you need a custom increment like every 2nd, 5th, or 10th number.
All four methods are documented in the GDK Integer class reference.
Real-World Use Cases
Batch Processing
Processing data in fixed-size batches is a natural fit for times():
Batch Processing
def allRecords = (1..47).collect { "Record-${it}" }
def batchSize = 10
def totalBatches = Math.ceil(allRecords.size() / batchSize).intValue()
println "Total records: ${allRecords.size()}"
println "Batch size: ${batchSize}"
println "Total batches: ${totalBatches}"
println()
totalBatches.times { batchNum ->
def start = batchNum * batchSize
def end = Math.min(start + batchSize, allRecords.size())
def batch = allRecords[start..<end]
println "Batch ${batchNum + 1}: Processing ${batch.size()} records (${batch.first()} to ${batch.last()})"
}
Output
Total records: 47 Batch size: 10 Total batches: 5 Batch 1: Processing 10 records (Record-1 to Record-10) Batch 2: Processing 10 records (Record-11 to Record-20) Batch 3: Processing 10 records (Record-21 to Record-30) Batch 4: Processing 10 records (Record-31 to Record-40) Batch 5: Processing 7 records (Record-41 to Record-47)
Stress Testing
Running stress tests or load simulations with a fixed number of iterations:
Stress Testing
def random = new Random(42)
def responseTimes = []
// Simulate 20 API calls
20.times { i ->
def responseTime = 50 + random.nextInt(200) // 50-250ms
responseTimes << responseTime
}
// Analyze results
def avg = (responseTimes.sum() / responseTimes.size()).round(1)
def sorted = responseTimes.sort()
def p50 = sorted[(sorted.size() * 0.5).intValue()]
def p95 = sorted[(sorted.size() * 0.95).intValue()]
def p99 = sorted[(sorted.size() * 0.99).intValue()]
println "Stress Test Results (20 requests):"
println " Average: ${avg}ms"
println " Min: ${responseTimes.min()}ms"
println " Max: ${responseTimes.max()}ms"
println " P50: ${p50}ms"
println " P95: ${p95}ms"
println " P99: ${p99}ms"
println " Under 200ms: ${responseTimes.count { it < 200 }} / ${responseTimes.size()}"
Output
Stress Test Results (20 requests): Average: 168.7ms Min: 55ms Max: 248ms P50: 172ms P95: 242ms P99: 248ms Under 200ms: 13 / 20
Progress Bar / Animation
Building text-based progress indicators:
Progress Bar
def totalSteps = 20
// Build a progress bar
totalSteps.times { step ->
def progress = ((step + 1) / totalSteps * 100).intValue()
def filled = (step + 1)
def empty = totalSteps - filled
def bar = "${'█' * filled}${'░' * empty}"
// In a real app, you'd use \r for overwriting
if ((step + 1) % 5 == 0 || step == 0) {
println "[${bar}] ${progress}%"
}
}
println "Done!"
Output
[█░░░░░░░░░░░░░░░░░░░] 5% [█████░░░░░░░░░░░░░░░] 25% [██████████░░░░░░░░░░] 50% [███████████████░░░░░] 75% [████████████████████] 100% Done!
Edge Cases and Best Practices
Edge Cases
// Zero times - does nothing, no error
print "Zero times: "
0.times { print "x" }
println "(nothing printed)"
// Negative number - also does nothing, no error
print "Negative: "
(-5).times { print "x" }
println "(nothing printed)"
// One time - runs exactly once
print "One time: "
1.times { print "runs once " }
println()
// Variable-driven - the number can come from anywhere
def userInput = 3
print "Variable (${userInput}): "
userInput.times { print "* " }
println()
// Large number - be careful with big values
def start = System.currentTimeMillis()
1_000_000.times { /* do nothing */ }
def elapsed = System.currentTimeMillis() - start
println "1 million empty iterations: ${elapsed}ms"
Output
Zero times: (nothing printed) Negative: (nothing printed) One time: runs once Variable (3): * * * 1 million empty iterations: 42ms
Best Practices:
- Use times() for simple repetition – when you just need to do something N times
- Name the parameter when the closure is multi-line –
{ index -> ... }is clearer than{ ... it ... } - Use upto() for 1-based iteration –
1.upto(n)is better thann.times { it + 1 } - Prefer (0..<n).collect{} over times() for building lists – since times() returns void, collect is more functional
- Don’t use times() when you need break – use a traditional for loop instead
- Validate the number before calling times() – negative values won’t crash, but they silently do nothing, which can hide bugs
Performance Considerations
A common question is whether times() is slower than a traditional for loop. Let’s measure:
Performance Comparison
def iterations = 10_000_000
// Traditional for loop
def start1 = System.nanoTime()
long sum1 = 0
for (int i = 0; i < iterations; i++) {
sum1 += i
}
def time1 = (System.nanoTime() - start1) / 1_000_000
// times() method
def start2 = System.nanoTime()
long sum2 = 0
iterations.times { sum2 += it }
def time2 = (System.nanoTime() - start2) / 1_000_000
println "10 million iterations:"
println " for loop: ${time1}ms (sum=${sum1})"
println " times(): ${time2}ms (sum=${sum2})"
println " Overhead: ${time2 - time1}ms"
Output
10 million iterations: for loop: 45ms (sum=49999995000000) times(): 210ms (sum=49999995000000) Overhead: 165ms
Yes, times() is slower than a raw for loop because it creates and invokes a closure on each iteration. But for realistic workloads – hundreds or thousands of iterations with actual logic inside – the closure overhead is negligible. Only consider switching to a for loop if you’re doing millions of iterations in a tight loop with trivial operations.
Rule of Thumb: If readability matters more than nanoseconds (it usually does), use
times(). If you’re writing a hot inner loop processing millions of elements, benchmark first.
Common Pitfalls
Pitfall 1: Trying to Use break or continue
Pitfall: No break/continue
// This WON'T compile:
// 10.times {
// if (it == 5) break // ERROR: break not allowed in closure
// }
// Workaround 1: Use a flag
def stop = false
10.times {
if (!stop) {
if (it == 5) {
stop = true
return // 'return' exits current closure iteration, not the loop
}
println "Processing ${it}"
}
}
// Workaround 2: Use a for loop instead
println "\nWith for loop:"
for (i in 0..9) {
if (i == 5) break
println "Processing ${i}"
}
Output
Processing 0 Processing 1 Processing 2 Processing 3 Processing 4 With for loop: Processing 0 Processing 1 Processing 2 Processing 3 Processing 4
Since times() uses a closure, you can’t use break or continue. The return keyword inside a closure only exits that single closure call – it doesn’t stop the loop. If you genuinely need early termination, use a for loop instead.
Pitfall 2: Assuming times() Returns a Value
Pitfall: void Return
// This won't work as expected:
def result = 5.times { it * 2 }
println "Result: ${result}" // null - times() returns void
// Instead, use collect with a range:
def result2 = (0..4).collect { it * 2 }
println "Result2: ${result2}"
Output
Result: null Result2: [0, 2, 4, 6, 8]
Remember: times() is for side effects (printing, modifying external state, sending requests). If you need to transform data, use (0..<n).collect { } instead – it returns a list.
Pitfall 3: Off-by-One with upto() vs step()
Pitfall: Inclusive vs Exclusive
// upto() is INCLUSIVE
print "upto(5): "
1.upto(5) { print "${it} " }
println() // 1 2 3 4 5 - includes 5
// step() is EXCLUSIVE
print "step(5): "
1.step(5, 1) { print "${it} " }
println() // 1 2 3 4 - does NOT include 5
// To match upto(5) with step(), use 6
print "step(6): "
1.step(6, 1) { print "${it} " }
println() // 1 2 3 4 5 - now includes 5
Output
upto(5): 1 2 3 4 5 step(5): 1 2 3 4 step(6): 1 2 3 4 5
This is one of the most common gotchas. upto() and downto() include the endpoint, while step() excludes it – just like Python’s range().
Conclusion
The Groovy times() loop is one of those small features that makes Groovy feel so much more expressive than Java. Instead of writing boilerplate for (int i = 0; i < n; i++), you just say n.times { }. It reads like English, eliminates off-by-one errors, and keeps your code focused on what matters – the action, not the loop mechanics.
We covered 10 practical examples, from basic repetition to test data generation, retry logic, batch processing, and stress testing. We also explored the related upto(), downto(), and step() methods that give you more control over your iteration ranges.
The bottom line is this: use times() for simple N-time repetition, upto()/downto() for specific ranges, and step() for custom increments. And remember – if you need break or a return value, reach for a for loop or collect() instead.
Summary
n.times { }repeats a closure exactly n times with index 0 to n-1- The implicit parameter
itholds the current index – name it explicitly for clarity upto()anddownto()are inclusive on both ends;step()is exclusive on the endtimes()returns void – use(0..<n).collect{}when you need a result list- No
break/continuein closures – use a for loop if you need early exit
If you also work with build tools, CI/CD pipelines, or cloud CLIs, check out Command Playground to practice 105+ CLI tools directly in your browser — no install needed.
Up next: Groovy Switch Statement – Pattern Matching Made Easy
Frequently Asked Questions
What does times() do in Groovy?
The times() method is called on an Integer and executes a closure that many times. For example, 5.times { println it } runs the closure 5 times, printing 0 through 4. It’s a cleaner alternative to writing a traditional for loop when you just need to repeat an action a fixed number of times.
Does Groovy times() start at 0 or 1?
The times() method always starts at 0 and ends at n-1. So 5.times {} iterates with values 0, 1, 2, 3, 4. If you need 1-based iteration, use 1.upto(5) {} instead, which gives you 1, 2, 3, 4, 5.
Can I use break inside Groovy times()?
No. Since times() uses a closure, the break keyword is not allowed. Using return inside the closure only exits that single iteration – it does not stop the loop. If you need early termination, use a traditional for loop or a flag variable to skip remaining iterations.
What is the difference between times() and upto() in Groovy?
times() is called on a single integer and iterates from 0 to n-1. upto() is called with a start and end value, iterating inclusively between them. Use times() for 0-based repetition (like 5.times{}) and upto() for specific ranges (like 1.upto(10){}). Additionally, step() lets you iterate with a custom increment.
Is Groovy times() slower than a for loop?
Yes, times() has slight overhead because it invokes a closure on each iteration. In benchmarks, it can be 3-5x slower than a raw for loop for millions of trivial iterations. However, for realistic workloads with actual logic inside the loop, the difference is negligible. Prioritize readability – only optimize if profiling shows it matters.
Related Posts
Previous in Series: Groovy each() Loop – Iterate Collections the Groovy Way
Next in Series: Groovy Switch Statement – Pattern Matching Made Easy
Related Topics You Might Like:
- Groovy For Loop – Classic and Range-Based Iteration
- Groovy each() Loop – Iterate Collections the Groovy Way
- Groovy Switch Statement – Pattern Matching Made Easy
This post is part of the Groovy & Grails Cookbook series on TechnoScripts.com

No comment