Groovy strings are explored here with 15 practical examples covering GStrings, multiline, trim, split, replace, and more. Complete tutorial tested on Groovy 5.x.
“In programming, strings are the glue that holds user-facing applications together. Master strings, and you master half the job.”
Bjarne Stroustrup, The C++ Programming Language
Last Updated: March 2026 | Tested on: Groovy 5.x, Java 17+ | Difficulty: Beginner to Intermediate | Reading Time: 18 minutes
If there’s one topic every Groovy developer needs to get right, it’s Groovy strings. Strings pop up everywhere – user input, database queries, API responses, log messages, file paths. And Groovy handles strings in ways that will genuinely make you enjoy working with text.
Unlike Java, where string manipulation often means chaining StringBuilder calls or writing verbose format strings, Groovy gives you GStrings for interpolation, triple-quoted strings for multi-line content, slashy strings for regex, and dozens of extra methods through the GDK. This Groovy string tutorial covers it all.
This post covers every string type Groovy offers, 15+ practical string methods, and the common pitfalls that trip up beginners. If you need specific string operations, we have dedicated posts on substrings, take(), drop(), and string comparison.
Table of Contents
What Are Groovy Strings?
Groovy has two main string types: java.lang.String (plain strings) and groovy.lang.GString (interpolated strings). On top of that, it offers multiple ways to create them – single quotes, double quotes, triple quotes, and slashy strings.
According to the official Groovy syntax documentation, Groovy supports five string literal forms. Each serves a different purpose, and knowing when to use which one makes your code cleaner and more readable.
Key Points:
- Single-quoted strings (
'hello') are plainjava.lang.String - Double-quoted strings (
"hello ${name}") are GStrings when they contain interpolation - Triple single-quoted (
'''...''') are multiline plain strings - Triple double-quoted (
"""...""") are multiline GStrings - Slashy strings (
/pattern/) are ideal for regular expressions - Groovy adds 60+ extra methods to Java’s String class through the GDK
5 Types of Strings in Groovy
| Type | Syntax | Interpolation | Multiline | Java Type |
|---|---|---|---|---|
| Single-quoted | 'hello' | No | No | java.lang.String |
| Double-quoted | "hello ${x}" | Yes | No | GString (or String if no $) |
| Triple single | '''hello''' | No | Yes | java.lang.String |
| Triple double | """hello ${x}""" | Yes | Yes | GString |
| Slashy | /pattern/ | Yes | Yes | GString (or String if no $) |
All 5 String Types
def name = "World"
// 1. Single-quoted - plain java.lang.String
def s1 = 'Hello, World!'
println "${s1} → ${s1.getClass().name}"
// 2. Double-quoted - GString with interpolation
def s2 = "Hello, ${name}!"
println "${s2} → ${s2.getClass().name}"
// 3. Triple single-quoted - multiline plain String
def s3 = '''Line 1
Line 2
Line 3'''
println "${s3} → ${s3.getClass().name}"
// 4. Triple double-quoted - multiline GString
def s4 = """Hello, ${name}!
Welcome to Groovy."""
println "${s4} → ${s4.getClass().name}"
// 5. Slashy string - great for regex
def s5 = /Hello, ${name}!/
println "${s5} → ${s5.getClass().name}"
Output
Hello, World! → java.lang.String Hello, World! → org.codehaus.groovy.runtime.GStringImpl Line 1 Line 2 Line 3 → java.lang.String Hello, World! Welcome to Groovy. → org.codehaus.groovy.runtime.GStringImpl Hello, World! → org.codehaus.groovy.runtime.GStringImpl
Notice how double-quoted strings without ${} become plain Strings, but the moment you add interpolation, they become GStrings. This is important to know because some APIs (like Map keys) behave differently with GStrings vs Strings.
Syntax and Basic Usage
String Creation
Creating Strings
// Literal strings
def str1 = 'Simple string'
def str2 = "GString: ${2 + 3}"
// From constructor
def str3 = new String("From constructor")
// From char array
def str4 = new String(['H', 'i'] as char[])
// From bytes
def str5 = new String([72, 101, 108, 108, 111] as byte[])
println str1
println str2
println str3
println str4
println str5
Output
Simple string GString: 5 From constructor Hi Hello
Key String Methods (Quick Reference)
| Method | Description | Example | Result |
|---|---|---|---|
length() / size() | String length | "hello".size() | 5 |
toUpperCase() | Convert to uppercase | "hello".toUpperCase() | HELLO |
toLowerCase() | Convert to lowercase | "HELLO".toLowerCase() | hello |
trim() | Remove whitespace | " hi ".trim() | hi |
contains() | Check if contains | "hello".contains("ell") | true |
replace() | Replace substring | "hello".replace("l","r") | herro |
split() | Split into array | "a,b,c".split(",") | [a, b, c] |
reverse() | Reverse string | "hello".reverse() | olleh |
take(n) | First n chars | "hello".take(3) | hel |
drop(n) | Skip first n chars | "hello".drop(2) | llo |
15 Practical String Examples
Example 1: String Concatenation
What we’re doing: Combining strings in different ways.
Example 1: Concatenation
def first = "Hello"
def last = "World"
// Method 1: Plus operator
println first + ", " + last + "!"
// Method 2: GString interpolation (preferred)
println "${first}, ${last}!"
// Method 3: concat()
println first.concat(", ").concat(last).concat("!")
// Method 4: StringBuilder (for heavy concatenation)
def sb = new StringBuilder()
sb.append(first).append(", ").append(last).append("!")
println sb.toString()
Output
Hello, World! Hello, World! Hello, World! Hello, World!
What happened here: All four methods produce the same result. In Groovy, GString interpolation (Method 2) is the preferred way – it’s the most readable and performs well. Only use StringBuilder for loops that concatenate hundreds or thousands of strings.
Example 2: GString Interpolation with Expressions
What we’re doing: Using expressions inside ${}.
Example 2: Expressions in GStrings
def price = 49.99
def qty = 3
println "Total: \$${price * qty}"
println "Discount: \$${(price * qty * 0.1).round(2)}"
println "Date: ${new Date().format('yyyy-MM-dd')}"
println "Random: ${new Random().nextInt(100)}"
println "Uppercase: ${'hello'.toUpperCase()}"
Output
Total: $149.97 Discount: $15.00 Date: 2026-03-08 Random: 42 Uppercase: HELLO
What happened here: You can put any Groovy expression inside ${} – method calls, arithmetic, object creation. The dollar sign for currency needs escaping with \$ to avoid being treated as interpolation. Learn more about GStrings in our GString guide.
Example 3: Multiline Strings
What we’re doing: Creating multiline strings with triple quotes.
Example 3: Multiline Strings
def name = "Alice"
// Triple single quotes - no interpolation
def sql = '''
SELECT *
FROM users
WHERE active = true
ORDER BY name
'''
// Triple double quotes - with interpolation
def email = """
Dear ${name},
Thank you for registering.
Your account is now active.
Best regards,
TechnoScripts Team
"""
println sql.trim()
println "---"
println email.trim()
Output
SELECT * FROM users WHERE active = true ORDER BY name --- Dear Alice, Thank you for registering. Your account is now active. Best regards, TechnoScripts Team
What happened here: Triple-quoted strings preserve all line breaks and formatting. Use triple single quotes for SQL, config files, and any text without variables. Use triple double quotes when you need interpolation. Both types are used extensively in Grails for HQL queries and email templates.
Example 4: String Padding and Centering
What we’re doing: Formatting strings with padding methods from the GDK.
Example 4: Padding
def items = ["Apple", "Banana", "Cherry"]
def prices = [1.50, 0.75, 2.25]
println "ITEM".padRight(15) + "PRICE"
println "-" * 20
items.eachWithIndex { item, i ->
println item.padRight(15) + "\$${prices[i]}"
}
println ""
println "centered".center(20, '=')
println "left".padRight(20, '.')
println "right".padLeft(20, '.')
Output
ITEM PRICE -------------------- Apple $1.50 Banana $0.75 Cherry $2.25 ======centered====== left................ ...............right
What happened here: Groovy’s GDK adds padRight(), padLeft(), and center() to String. The * operator repeats a string – "-" * 20 creates twenty dashes. These are perfect for formatting console output and reports.
Example 5: String to Number Conversion
What we’re doing: Converting strings to various number types.
Example 5: String to Number
def numStr = "42"
def decStr = "3.14"
println "toInteger: ${numStr.toInteger()} (${numStr.toInteger().getClass().simpleName})"
println "toLong: ${numStr.toLong()} (${numStr.toLong().getClass().simpleName})"
println "toFloat: ${decStr.toFloat()} (${decStr.toFloat().getClass().simpleName})"
println "toDouble: ${decStr.toDouble()} (${decStr.toDouble().getClass().simpleName})"
println "toBigDecimal: ${decStr.toBigDecimal()} (${decStr.toBigDecimal().getClass().simpleName})"
// Safe conversion - returns null instead of exception
println "isNumber: ${'abc'.isNumber()}"
println "isNumber: ${'123'.isNumber()}"
println "isInteger: ${'42'.isInteger()}"
Output
toInteger: 42 (Integer) toLong: 42 (Long) toFloat: 3.14 (Float) toDouble: 3.14 (Double) toBigDecimal: 3.14 (BigDecimal) isNumber: false isNumber: true isInteger: true
What happened here: Groovy adds conversion methods directly to String. Always check with isNumber() or isInteger() before converting to avoid exceptions. For a complete guide on conversions, see Groovy String To Integer.
Example 6: Substring and take/drop
What we’re doing: Extracting parts of strings using multiple approaches.
Example 6: Extracting Parts
def text = "Hello, World!" // Java's substring println text.substring(0, 5) // Hello println text.substring(7) // World! // Groovy's take/drop (safer - no IndexOutOfBounds) println text.take(5) // Hello println text.drop(7) // World! // Groovy subscript operator println text[0..4] // Hello println text[7..-1] // World! println text[-6..-1] // orld! // take is safe with lengths > string size println "Hi".take(100) // Hi (no exception!)
Output
Hello World! Hello World! Hello World! World! Hi
What happened here: Groovy gives you three ways to extract substrings. The subscript operator (text[0..4]) uses ranges and supports negative indices. The take() method is the safest – it never throws an exception, even if you request more characters than the string contains. More details in our substring guide and take() guide.
Example 7: Replace and ReplaceAll
What we’re doing: Replacing text within strings.
Example 7: Replace
def text = "The quick brown fox jumps over the lazy dog"
// Simple replace
println text.replace("fox", "cat")
// Replace first occurrence
println text.replaceFirst("the", "THE")
// Replace with regex
println text.replaceAll(/[aeiou]/, "*")
// Groovy's tr (transliterate - like Unix tr command)
println "hello".tr("aeiou", "*")
println "Hello World".tr("a-z", "A-Z")
Output
The quick brown cat jumps over the lazy dog The quick brown fox jumps over THE lazy dog Th* q**ck br*wn f*x j*mps *v*r th* l*zy d*g h*ll* HELLO WORLD
What happened here: replace() does literal replacement. replaceAll() uses regex patterns. And Groovy’s tr() method transliterates characters – like Unix’s tr command.
Example 8: Split and Tokenize
What we’re doing: Breaking strings into pieces.
Example 8: Split and Tokenize
def csv = "apple,banana,,cherry,,"
// split() - keeps empty strings
def parts1 = csv.split(",")
println "split: ${parts1 as List} (${parts1.length} elements)"
// tokenize() - removes empty strings (Groovy GDK)
def parts2 = csv.tokenize(",")
println "tokenize: ${parts2} (${parts2.size()} elements)"
// Split with regex
def words = "Hello World Groovy".split(/\s+/)
println "regex split: ${words as List}"
// Split with limit
def limited = "a:b:c:d:e".split(":", 3)
println "limited: ${limited as List}"
Output
split: [apple, banana, , cherry] (4 elements) tokenize: [apple, banana, cherry] (3 elements) regex split: [Hello, World, Groovy] limited: [a, b, c:d:e]
What happened here: The key difference – split() returns a String array and keeps empty elements. tokenize() returns a List and skips empties. Choose based on whether empty values matter to your logic. We cover this in detail in the split and tokenize posts.
Example 9: Trim and Strip
What we’re doing: Removing whitespace from strings.
Example 9: Trimming
def messy = " Hello, World! "
println "'${messy.trim()}'" // Both sides
println "'${messy.stripLeading()}'" // Left only (Java 11+)
println "'${messy.stripTrailing()}'" // Right only (Java 11+)
// Groovy's stripIndent - removes common leading whitespace
def indented = """
Line 1
Line 2
Line 3 (indented more)
Line 4
""".stripIndent().trim()
println indented
Output
'Hello, World!'
'Hello, World! '
' Hello, World!'
Line 1
Line 2
Line 3 (indented more)
Line 4
What happened here: stripIndent() is a Groovy GDK method that finds the smallest indentation across all lines and removes it. Incredibly useful when you have triple-quoted strings inside indented code blocks.
Example 10: String Comparison
What we’re doing: Comparing strings using different methods.
Example 10: Comparison
def a = "Hello"
def b = "hello"
def c = "Hello"
// equals (case-sensitive)
println "a == c: ${a == c}" // true (Groovy uses equals(), not identity!)
println "a == b: ${a == b}" // false
// Case-insensitive
println "equalsIgnoreCase: ${a.equalsIgnoreCase(b)}" // true
// Spaceship operator for comparison
println "a <=> b: ${a <=> b}" // negative (H < h in ASCII)
println "a <=> c: ${a <=> c}" // 0 (equal)
// Identity check (same object in memory)
println "a.is(c): ${a.is(c)}" // may be true (string pool)
Output
a == c: true a == b: false equalsIgnoreCase: true a <=> b: -1 a <=> c: 0 a.is(c): true
What happened here: In Groovy, == calls equals(), not reference comparison like Java. This means == is safe for string comparison – no need for .equals(). For identity comparison, use .is(). Full details in Groovy Compare Strings.
Example 11: String Reverse
What we’re doing: Reversing strings and checking palindromes.
Example 11: Reverse
println "Hello".reverse()
println "12345".reverse()
// Palindrome check
def isPalindrome = { str ->
def clean = str.toLowerCase().replaceAll(/[^a-z0-9]/, '')
clean == clean.reverse()
}
println "madam: ${isPalindrome('madam')}"
println "hello: ${isPalindrome('hello')}"
println "A man a plan a canal Panama: ${isPalindrome('A man a plan a canal Panama')}"
Output
olleH 54321 madam: true hello: false A man a plan a canal Panama: true
What happened here: Groovy’s reverse() is a GDK method added to String. Combined with replaceAll() and a closure, you get a clean palindrome checker in just a few lines.
Example 12: String Multiply and Repeat
What we’re doing: Repeating strings using the multiply operator.
Example 12: Multiply
println "Ha" * 3
println "-" * 40
println "abc " * 4
// Building a simple progress bar
def progress = 7
def total = 10
def bar = "█" * progress + "░" * (total - progress)
println "[${bar}] ${progress * 10}%"
Output
HaHaHa ---------------------------------------- abc abc abc abc [███████░░░] 70%
What happened here: Groovy overloads the * operator for strings. "abc" * 3 repeats the string 3 times. This is much cleaner than Java’s String.repeat(3) (Java 11+) or manual loops.
Example 13: Regular Expression Matching
What we’re doing: Using Groovy’s regex operators with strings.
Example 13: Regex Matching
def email = "user@example.com"
def phone = "123-456-7890"
// Match operator (==~) - returns boolean
println "Valid email: ${email ==~ /[\w.]+@[\w.]+\.\w+/}"
println "Valid phone: ${phone ==~ /\d{3}-\d{3}-\d{4}/}"
// Find operator (=~) - returns Matcher
def text = "Call 123-456-7890 or 098-765-4321"
def matcher = text =~ /\d{3}-\d{3}-\d{4}/
println "Found ${matcher.count} phone numbers"
matcher.each { println " ${it}" }
Output
Valid email: true Valid phone: true Found 2 phone numbers 123-456-7890 098-765-4321
What happened here: Groovy’s ==~ operator checks for an exact match (returns boolean). The =~ operator finds all matches (returns a Matcher). Slashy strings (/pattern/) make regex patterns clean – no double-backslash escaping needed.
Example 14: String Case Conversion
What we’re doing: Converting between different case formats.
Example 14: Case Conversion
def text = "hello world groovy"
println text.toUpperCase()
println text.toLowerCase()
println text.capitalize() // First char uppercase
// Title Case - capitalize each word
println text.split(' ').collect { it.capitalize() }.join(' ')
// Groovy's uncapitalize
println "HelloWorld".uncapitalize()
Output
HELLO WORLD GROOVY hello world groovy Hello world groovy Hello World Groovy helloWorld
What happened here: capitalize() and uncapitalize() are Groovy GDK methods. Title case isn’t built-in, but it’s a one-liner with split, collect, and join.
Example 15: String Iteration
What we’re doing: Iterating over characters in a string.
Example 15: String Iteration
def word = "Groovy"
// each character
word.each { ch -> print "${ch}-" }
println()
// eachWithIndex
word.eachWithIndex { ch, i -> print "${i}:${ch} " }
println()
// collect - transform each character
println word.toList().collect { it.toUpperCase() }
// Count specific characters
def vowels = word.toList().count { it.toLowerCase() in ['a','e','i','o','u'] }
println "Vowels in '${word}': ${vowels}"
// Unique characters
println "Unique chars: ${word.toList().unique()}"
Output
G-r-o-o-v-y- 0:G 1:r 2:o 3:o 4:v 5:y [G, R, O, O, V, Y] Vowels in 'Groovy': 2 Unique chars: [G, r, o, v, y]
What happened here: Strings in Groovy can be iterated like collections. Methods like each() and eachWithIndex() work directly on strings. For collect() and count() with closures, convert to a list first with toList().
GString Interpolation Details
There’s a subtle but important detail about GStrings: they evaluate lazily in some cases.
GString Lazy Evaluation
// GString with a closure - evaluates lazily
def counter = 0
def message = "Count: ${-> ++counter}"
println message // evaluates now
println message // evaluates again - counter incremented!
println message // and again!
// GString vs String for Map keys (gotcha!)
def map = [:]
def key = "name"
map["${key}"] = "Alice" // GString key
map[key] = "Bob" // String key
println map.size() // 2! Different keys because GString != String
println map
Output
Count: 1 Count: 2 Count: 3 2 [name:Alice, name:Bob]
When you put a closure (${-> expr}) inside a GString, it re-evaluates every time the GString is used. And watch out for the map key gotcha – a GString key and a String key are different objects even if they contain the same text.
Deprecated vs Modern Approach
Old vs Modern String Operations
// Old way: Java-style string building
def name = "Alice"
def age = 30
// Deprecated approach (Java 5 style)
String old1 = String.format("Name: %s, Age: %d", name, age)
println old1
// Modern approach: GString
String modern1 = "Name: ${name}, Age: ${age}"
println modern1
// Old way: StringBuilder for simple concat
def old2 = new StringBuilder().append("Hello, ").append(name).toString()
println old2
// Modern approach: GString
def modern2 = "Hello, ${name}"
println modern2
Output
Name: Alice, Age: 30 Name: Alice, Age: 30 Hello, Alice Hello, Alice
Migration Note:
String.format()andStringBuilderstill work in Groovy, but GString interpolation is preferred for readability. Only use StringBuilder for loop-heavy concatenation.
Edge Cases and Best Practices
Best Practices Summary
DO:
- Use single quotes for static strings (no interpolation needed)
- Use double quotes when you need
${}interpolation - Use triple quotes for multiline strings (SQL, templates, emails)
- Use slashy strings for regex patterns
- Use
==for string comparison (it calls.equals())
DON’T:
- Use GStrings as Map keys (they don’t equal String keys)
- Concatenate strings in loops with
+– use StringBuilder or collect().join() - Forget to escape
$in double-quoted strings when you mean literal dollar signs
Performance Considerations
For most string operations, performance is not a concern. But here are some tips for high-volume processing:
Performance Tips
// Slow: concatenation in a loop
def slow() {
def result = ""
1000.times { result += "x" }
return result.length()
}
// Fast: StringBuilder in a loop
def fast() {
def sb = new StringBuilder()
1000.times { sb.append("x") }
return sb.toString().length()
}
// Also fast: collect and join
def alsoFast() {
return (1..1000).collect { "x" }.join()
}
println "All produce strings of length: ${slow()}"
Output
All produce strings of length: 1000
String concatenation with + creates a new String object every iteration – O(n²) performance. StringBuilder and collect/join are both O(n).
Common Pitfalls
Pitfall 1: GString vs String in Switch Statements
Switch Pitfall
def type = "admin"
def role = "${type}" // This is a GString
switch (role) {
case 'admin': // This is a String
println "Admin access granted"
break
default:
println "No match"
}
Output
Admin access granted
This actually works because Groovy’s switch uses isCase() which handles GString/String comparison. But it’s still good practice to use .toString() on GStrings when exact type matching matters.
Pitfall 2: Single vs Double Quotes with Dollar Signs
Dollar Sign Pitfall
def price = 99.99
// Wrong - $ is literal in single quotes
println 'Price: $price' // Price: $price
// Correct - interpolation with double quotes
println "Price: \$${price}" // Price: $99.99
// Also correct - escape dollar for literal
println "Price: \$${price} USD" // Price: $99.99 USD
Output
Price: $price Price: $99.99 Price: $99.99 USD
Conclusion
We covered a lot of ground in this Groovy string tutorial – from the five string types to 15 practical examples, GString internals, and performance tips. Strings in Groovy are genuinely more pleasant to work with than in Java, thanks to GString interpolation, multiline strings, the GDK’s extra methods, and operator overloading.
The key things to remember: use single quotes for plain strings, double quotes for interpolation, triple quotes for multiline, and slashy strings for regex. And always use == for comparison – it’s safe in Groovy.
For deeper dives into specific string operations, check out the related posts below.
Summary
- Groovy has 5 string types: single, double, triple-single, triple-double, and slashy
- GStrings (double-quoted) support
${expression}interpolation - The GDK adds 60+ methods to String – reverse(), take(), drop(), capitalize(), and more
==is safe for string comparison in Groovy (calls .equals())- Use
tokenize()instead ofsplit()when you want to skip empty elements
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 String To Integer – All Conversion Methods
Frequently Asked Questions
What is the difference between String and GString in Groovy?
A String (single-quoted) is a plain java.lang.String with no interpolation. A GString (double-quoted with ${}) is a groovy.lang.GString that evaluates expressions at runtime. GStrings are automatically converted to Strings when needed, but they are different types internally.
How do I compare strings in Groovy?
Use the == operator. In Groovy, == calls .equals() (not reference comparison like Java), so it’s safe for string comparison. For case-insensitive comparison, use .equalsIgnoreCase(). For ordering, use the spaceship operator (<=>).
What are triple-quoted strings in Groovy?
Triple-quoted strings (''' or """) preserve line breaks and indentation. Use triple single-quotes for multiline text without interpolation (SQL, templates). Use triple double-quotes when you need ${} interpolation in multiline strings.
How do I convert a Groovy string to a number?
Use the built-in methods: toInteger(), toLong(), toFloat(), toDouble(), or toBigDecimal(). Always check first with isNumber() or isInteger() to avoid NumberFormatException. Example: ’42’.toInteger() returns 42.
What is a slashy string in Groovy?
A slashy string (/pattern/) is a string delimited by forward slashes. It’s primarily used for regular expressions because backslashes don’t need escaping. For example, /\d+/ matches digits – you write one backslash instead of Java’s double backslash.
Related Posts
Previous in Series: Groovy -e Command Line Option – Run Scripts Instantly
Next in Series: Groovy String To Integer – All Conversion Methods
Related Topics You Might Like:
- Groovy GString – String Interpolation Made Easy
- Groovy Multiline String – Heredoc and Triple Quotes
- Groovy Regular Expressions – Pattern Matching
This post is part of the Groovy & Grails Cookbook series on TechnoScripts.com

No comment