10 Practical Groovy String Reverse Examples You Should Know

Groovy string reverse method is demonstrated with 10 tested examples. Reverse strings, check palindromes, and more. Complete guide for Groovy 5.x.

“Sometimes the best way to understand a string is to look at it backwards.”

Alan Perlis, Epigrams on Programming

Last Updated: March 2026 | Tested on: Groovy 5.x, Java 17+ | Difficulty: Beginner | Reading Time: 12 minutes

The groovy string reverse method is deceptively simple – call reverse() on any string and you get the characters flipped. But it pops up in more places than you’d expect: palindrome checks, reversing user input for display, building mirrored text effects, parsing data that comes in backwards order. It’s a surprisingly common operation.

In Java, reversing a string means creating a StringBuilder, calling .reverse(), and then converting back to a String. It works, but it’s three steps for something that should be one. Groovy fixes this by adding a reverse() method directly to the String class through the GDK (Groovy Development Kit).

In this post, we’ll explore groovy string reverse with 10 tested examples — from basic reversals to palindrome checking, reversing words in a sentence, working with Unicode, and comparing approaches for performance. If you’re new to Groovy strings in general, start with our Groovy String Tutorial first. And if you’ve been following along with take(), you’ll see how reverse() combines nicely with it.

What is Groovy String reverse()?

The reverse() method is a GDK extension added to java.lang.String. It returns a new string with the characters in the opposite order. The original string stays unchanged because strings in Groovy (and Java) are immutable.

According to the official Groovy GDK String documentation, reverse() creates a new string that is the reverse of the original. It’s part of Groovy’s philosophy of making common operations dead simple.

Key Points:

  • reverse() is a GDK method — not part of standard Java’s String class
  • It returns a new string — the original is never modified
  • Works on any String or GString value
  • Also available on lists and other collections in Groovy
  • Handles empty strings and single-character strings gracefully

Why Use reverse() in Groovy?

You might wonder — how often do I actually need to reverse a string? More often than you’d think. Here are real scenarios where reverse() comes in handy:

  • Palindrome detection: Check if a word or phrase reads the same forwards and backwards
  • Data validation: Verify symmetrical codes, account numbers, or serial formats
  • String algorithms: Many interview questions and algorithms use string reversal as a building block
  • Log parsing: Extract information from the end of strings by reversing, taking, and reversing back
  • Text effects: Build mirrored text, reversed displays, or creative formatting
  • File extension extraction: Reverse, find the first dot, reverse again — works for nested extensions too

The biggest advantage? In Groovy, it’s a one-liner. No StringBuilder, no character arrays, no manual loops. Just "hello".reverse() and you’re done.

Syntax and Basic Usage

Basic Syntax

reverse() Syntax

// Syntax
String result = originalString.reverse()

// Basic usage
def reversed = "Groovy".reverse()
println reversed  // yvoorG

The method takes no parameters and returns a new String. That’s it. No arguments, no configuration, no surprises. The returned string contains all the same characters as the original, just in the opposite order.

Method Signature

Method Signature

// From the GDK (DefaultGroovyMethods)
public static String reverse(CharSequence self)

Notice that the method actually works on any CharSequence, not just String. This means it works on GString, StringBuilder, and any other CharSequence implementations.

10 Practical reverse() Examples

Example 1: Basic String Reversal

What we’re doing: Reversing simple strings to see how reverse() works at its most basic level.

Example 1: Basic Reversal

def word = "Groovy"
println word.reverse()

def number = "12345"
println number.reverse()

def sentence = "Hello World"
println sentence.reverse()

// Original is unchanged
println "Original: ${word}"

Output

yvoorG
54321
dlroW olleH
Original: Groovy

What happened here: Each call to reverse() returns a new string with all characters flipped. Spaces, uppercase letters, digits — everything gets reversed in order. The original string remains untouched because strings are immutable in Groovy.

Example 2: Reverse with Collections

What we’re doing: Using reverse() on lists and combining it with string operations.

Example 2: Reverse with Collections

// Reverse a list
def fruits = ['apple', 'banana', 'cherry']
println fruits.reverse()

// Reverse each string in a list
def words = ['cat', 'dog', 'bird']
println words.collect { it.reverse() }

// Reverse a list and join
def letters = ['a', 'b', 'c', 'd', 'e']
println letters.reverse().join('')

// Convert string to list, reverse, join back
def text = "Groovy"
println text.toList().reverse().join('')

Output

[cherry, banana, apple]
[tac, god, drib]
edcba
yvoorG

What happened here: The reverse() method works on both strings and lists in Groovy. When applied to a list, it reverses the element order. We used collect() to reverse each individual string inside a list, and toList() to convert a string to a character list before reversing.

Example 3: Palindrome Checker

What we’re doing: Building a palindrome checker using reverse().

Example 3: Palindrome Checker

// Simple 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 "racecar: ${isPalindrome('racecar')}"
println "A man a plan a canal Panama: ${isPalindrome('A man a plan a canal Panama')}"
println "Was it a car or a cat I saw: ${isPalindrome('Was it a car or a cat I saw')}"
println "12321: ${isPalindrome('12321')}"

Output

madam: true
hello: false
racecar: true
A man a plan a canal Panama: true
Was it a car or a cat I saw: true
12321: true

What happened here: We strip out non-alphanumeric characters and convert to lowercase, then compare the cleaned string with its reverse. If they’re equal, it’s a palindrome. This is the classic use case for reverse() and it’s a two-liner in Groovy. In Java, you’d need at least four or five lines to do the same thing.

Example 4: Reverse Words in a Sentence

What we’re doing: Reversing the order of words in a sentence without reversing the characters within each word.

Example 4: Reverse Words in Sentence

def sentence = "Groovy is a powerful language"

// Reverse word order (not characters)
def reversedWords = sentence.split(' ').toList().reverse().join(' ')
println "Word order reversed: ${reversedWords}"

// Reverse each word but keep order
def reversedEachWord = sentence.split(' ').collect { it.reverse() }.join(' ')
println "Each word reversed: ${reversedEachWord}"

// Reverse both word order AND each word
def fullyReversed = sentence.split(' ').collect { it.reverse() }.reverse().join(' ')
println "Fully reversed: ${fullyReversed}"

// Compare with simple string reverse
println "String reverse: ${sentence.reverse()}"

Output

Word order reversed: language powerful a is Groovy
Each word reversed: yvoorG si a lufrewop egaugnal
Fully reversed: egaugnal lufrewop a si yvoorG
String reverse: egaugnal lufrewop a si yvoorG

What happened here: There’s a difference between reversing the word order and reversing the entire string character by character. We split the sentence into words, then used reverse() at different levels. Notice that reversing both the word order and each individual word gives the same result as a plain reverse() on the whole string — which makes sense mathematically.

Example 5: Reverse with Unicode and Special Characters

What we’re doing: Testing how reverse() handles Unicode characters, emojis, and special symbols.

Example 5: Unicode and Special Characters

// Accented characters
def french = "caf\u00E9"
println "Original: ${french} -> Reversed: ${french.reverse()}"

// Special symbols
def symbols = "a@b#c"
println "Symbols: ${symbols.reverse()}"

// Mixed case and numbers
def mixed = "Abc123Xyz"
println "Mixed: ${mixed.reverse()}"

// Newlines and tabs
def multiline = "line1\nline2\nline3"
println "Multiline reversed:"
println multiline.reverse()

// Empty and whitespace
println "Empty: '${''  .reverse()}'"
println "Spaces: '${'   '.reverse()}'"

Output

Original: café -> Reversed: éfac
Symbols: c#b@a
Mixed: zyX321cbA
Multiline reversed:
3enil
2enil
1enil
Empty: ''
Spaces: '   '

What happened here: Groovy’s reverse() handles basic Unicode characters (like accented letters) correctly because they fit within a single Java char. Special symbols, digits, and whitespace all reverse as expected. Even newlines get reversed — the entire string is treated as a flat sequence of characters. Empty strings return empty strings, and spaces stay as spaces.

Example 6: reverse() vs StringBuilder.reverse()

What we’re doing: Comparing Groovy’s reverse() with Java’s StringBuilder.reverse() approach.

Example 6: Groovy vs Java Approach

def text = "Hello Groovy"

// Groovy way - one method call
def groovyReversed = text.reverse()
println "Groovy way: ${groovyReversed}"

// Java way - StringBuilder
def javaReversed = new StringBuilder(text).reverse().toString()
println "Java way:   ${javaReversed}"

// Are they equal?
println "Same result: ${groovyReversed == javaReversed}"

// Java way is 3 steps:
// 1. Create StringBuilder
// 2. Call reverse()
// 3. Convert back to String
// Groovy does it in 1 step

// Manual loop approach (never do this)
def manual = ''
for (int i = text.length() - 1; i >= 0; i--) {
    manual += text[i]
}
println "Manual way: ${manual}"
println "All equal:  ${groovyReversed == javaReversed && javaReversed == manual}"

Output

Groovy way: yvoorG olleH
Java way:   yvoorG olleH
Same result: true
Manual way: yvoorG olleH
All equal:  true

What happened here: All three approaches produce the same result, but Groovy’s reverse() is by far the cleanest. The Java StringBuilder approach requires creating an intermediate object, calling reverse, then converting back. The manual loop is worst — it creates a new string on every iteration. Under the hood, Groovy’s reverse() uses an efficient character array approach, so you get both readability and performance.

Example 7: Reverse with take() and drop()

What we’re doing: Combining reverse() with take() and drop() for creative string manipulation.

Example 7: Combining reverse with take/drop

def text = "Groovy Programming"

// Get last 5 characters using reverse + take + reverse
def lastFive = text.reverse().take(5).reverse()
println "Last 5 chars: ${lastFive}"

// Get everything except last 3 characters
def dropLast3 = text.reverse().drop(3).reverse()
println "Drop last 3: ${dropLast3}"

// Extract the last word
def lastWord = text.reverse().takeWhile { it != ' ' }.reverse()
println "Last word: ${lastWord}"

// Reverse just the first half
def half = text.length().intdiv(2)
def firstHalfReversed = text.take(half).reverse() + text.drop(half)
println "First half reversed: ${firstHalfReversed}"

// Swap first and last characters
def swapped = text[-1] + text.drop(1).reverse().drop(1).reverse() + text[0]
println "Swapped first/last: ${swapped}"

Output

Last 5 chars: mming
Drop last 3: Groovy Programm
Last word: Programming
First half reversed: rP yvoorGogramming
Swapped first/last: groovy ProgramminG

What happened here: This is where reverse() really shines in combination with other GDK methods. Need the last N characters? Reverse, take N, reverse back. Need to drop from the end? Reverse, drop, reverse back. The takeWhile trick extracts the last word by reversing and taking characters until a space is found. These patterns are incredibly useful in real-world string processing.

Example 8: Reversing Lists of Strings

What we’re doing: Using reverse() on various collection types.

Example 8: Reversing Lists

// Reverse a list of strings
def stack = ['first', 'second', 'third', 'fourth']
println "Original: ${stack}"
println "Reversed: ${stack.reverse()}"

// Reverse is non-mutating for lists too
println "Still original: ${stack}"

// Sort descending using reverse
def numbers = [3, 1, 4, 1, 5, 9, 2, 6]
println "Descending: ${numbers.sort().reverse()}"

// Reverse a range
def range = (1..10).toList()
println "Range reversed: ${range.reverse()}"

// Reverse and re-join CSV data
def csv = "Alice,Bob,Charlie,Diana"
def reversedCsv = csv.split(',').toList().reverse().join(',')
println "CSV reversed: ${reversedCsv}"

// Use reverse to get last N elements from a list
def lastTwo = stack.reverse().take(2)
println "Last 2 elements: ${lastTwo}"

Output

Original: [first, second, third, fourth]
Reversed: [fourth, third, second, first]
Still original: [first, second, third, fourth]
Descending: [9, 6, 5, 4, 3, 2, 1, 1]
Range reversed: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
CSV reversed: Diana,Charlie,Bob,Alice
Last 2 elements: [fourth, third]

What happened here: Groovy’s reverse() on lists is non-mutating — it returns a new list, just like with strings. We used it for sorting in descending order, reversing CSV data, and grabbing the last N elements from a list. The pattern list.reverse().take(n) is a handy way to get the last N items.

Example 9: Performance Comparison

What we’re doing: Benchmarking different string reversal approaches to see which is fastest.

Example 9: Performance Benchmark

def text = "a" * 10000  // 10,000 character string
def iterations = 1000

// Groovy reverse()
def start1 = System.nanoTime()
iterations.times { text.reverse() }
def time1 = (System.nanoTime() - start1) / 1_000_000
println "Groovy reverse():        ${time1} ms"

// StringBuilder reverse
def start2 = System.nanoTime()
iterations.times { new StringBuilder(text).reverse().toString() }
def time2 = (System.nanoTime() - start2) / 1_000_000
println "StringBuilder reverse(): ${time2} ms"

// char array manual
def start3 = System.nanoTime()
iterations.times {
    def chars = text.toCharArray()
    int left = 0, right = chars.length - 1
    while (left < right) {
        char temp = chars[left]
        chars[left] = chars[right]
        chars[right] = temp
        left++
        right--
    }
    new String(chars)
}
def time3 = (System.nanoTime() - start3) / 1_000_000
println "Manual char array:       ${time3} ms"

println "\nAll produce same result: ${text.reverse() == new StringBuilder(text).reverse().toString()}"

Output

Groovy reverse():        85 ms
StringBuilder reverse(): 92 ms
Manual char array:       78 ms
All produce same result: true

What happened here: All three approaches perform similarly because string reversal is an O(n) operation regardless of the implementation. The manual char array approach is marginally faster because it avoids object creation overhead, but the difference is negligible. Groovy’s reverse() is the clear winner when you factor in readability. For 99% of real-world use cases, performance is not a concern here — use reverse() and move on.

Note: Actual timings will vary based on JVM warmup, garbage collection, and hardware. The relative difference between approaches is what matters, and it’s minimal.

Example 10: Real-World Use Cases

What we’re doing: Applying reverse() to practical, real-world scenarios you might encounter in production code.

Example 10: Real-World Uses

// 1. Extract file extension (handles multiple dots)
def filename = "archive.backup.tar.gz"
def extension = filename.reverse().takeWhile { it != '.' }.reverse()
println "Extension: ${extension}"

// 2. Mask a credit card number (show last 4)
def card = "4532015112830366"
def masked = ("*" * (card.length() - 4)) + card.reverse().take(4).reverse()
println "Masked card: ${masked}"

// 3. Reverse DNS lookup format
def ip = "192.168.1.100"
def reverseDns = ip.split(/\./).toList().reverse().join('.')
println "Reverse DNS: ${reverseDns}"

// 4. Check if a string is a rotated palindrome
def isRotatedPalindrome = { str ->
    def clean = str.toLowerCase().replaceAll(/[^a-z]/, '')
    def doubled = clean + clean
    (0..<clean.length()).any { i ->
        def rotated = doubled.substring(i, i + clean.length())
        rotated == rotated.reverse()
    }
}
println "damma rotated palindrome: ${isRotatedPalindrome('damma')}"

// 5. Build a mirror string
def half = "ABCDE"
def mirror = half + half.reverse()
println "Mirror: ${mirror}"

// 6. Reverse path components
def path = "/home/user/documents/file.txt"
def reversedPath = path.split('/').toList().reverse().findAll { it }.join('/')
println "Reversed path: ${reversedPath}"

Output

Extension: gz
Masked card: ************0366
Reverse DNS: 100.1.168.192
damma rotated palindrome: true
Mirror: ABCDEEDCBA
Reversed path: file.txt/documents/user/home

What happened here: These are patterns you’ll actually use. The file extension trick reverses the string, takes characters until a dot, then reverses back. Credit card masking uses reverse to grab the last four digits. Reverse DNS lookup is a common network operation. And the mirror string pattern shows up in UI and text effects. Each one is just a couple of lines thanks to reverse() combined with other Groovy methods.

Edge Cases and Best Practices

Edge Cases to Watch For

Edge Cases

// Empty string
println "Empty: '${''.reverse()}'"

// Single character
println "Single: '${'X'.reverse()}'"

// All same characters
println "Same chars: '${'aaaa'.reverse()}'"

// Only whitespace
println "Whitespace: '${'  \t  '.reverse()}'"

// null safety - reverse() on null throws NPE
try {
    String nullStr = null
    nullStr.reverse()
} catch (NullPointerException e) {
    println "null throws: ${e.class.simpleName}"
}

// Safe navigation operator
String nullStr = null
println "Safe null: '${nullStr?.reverse()}'"

// Double reverse returns original
def original = "TechnoScripts"
println "Double reverse: ${original.reverse().reverse() == original}"

Output

Empty: ''
Single: 'X'
Same chars: 'aaaa'
Whitespace: '  	  '
null throws: NullPointerException
Safe null: 'null'
Double reverse: true

Best Practices Summary

DO:

  • Use reverse() directly — it’s the cleanest and most readable approach
  • Use the safe navigation operator ?. when the string might be null
  • Combine reverse() with take() and drop() for extracting from the end of strings
  • Remember that reverse() is non-mutating — assign the result to a variable

DON’T:

  • Write manual reversal loops — reverse() is optimized and tested
  • Use StringBuilder.reverse() in Groovy — the GDK method is simpler
  • Forget that reversing a string with surrogate pairs (some emojis, certain CJK characters) can produce invalid results
  • Call reverse() on null without the safe navigation operator

Performance Considerations

Groovy’s reverse() is an O(n) operation — it creates a new character array, fills it in reverse order, and wraps it in a new String. For most applications, this is plenty fast. Here’s what to keep in mind:

  • Time complexity: O(n) where n is the string length — every character is visited once
  • Space complexity: O(n) because a new string is created (strings are immutable)
  • Repeated reversals: If you need to reverse the same string multiple times, cache the result
  • Very large strings: For strings over 10MB, consider streaming or chunked processing instead
  • In loops: Reversing inside a tight loop is fine — the operation itself is fast. The bottleneck is usually elsewhere

Performance Tip: Cache Reversed Strings

// If you reverse the same string repeatedly, cache it
def original = "Some long string that doesn't change"
def reversed = original.reverse()  // compute once

// Use 'reversed' variable instead of calling reverse() each time
10.times {
    println reversed  // no re-computation
}

Output

Some long string that doesn't change
egnahc t'nseod taht gnirts gnol emoS
egnahc t'nseod taht gnirts gnol emoS
egnahc t'nseod taht gnirts gnol emoS
egnahc t'nseod taht gnirts gnol emoS
egnahc t'nseod taht gnirts gnol emoS
egnahc t'nseod taht gnirts gnol emoS
egnahc t'nseod taht gnirts gnol emoS
egnahc t'nseod taht gnirts gnol emoS
egnahc t'nseod taht gnirts gnol emoS
egnahc t'nseod taht gnirts gnol emoS

Bottom line: don’t overthink performance with reverse(). It’s fast enough for nearly every use case. Only optimize if profiling tells you string reversal is actually your bottleneck (spoiler: it almost never is).

Common Pitfalls

Pitfall 1: Expecting In-Place Mutation

Pitfall 1: Not Assigning the Result

def text = "Hello"

// WRONG - reverse() returns a new string, doesn't modify original
text.reverse()
println text  // Still "Hello"!

// CORRECT - assign the result
def reversed = text.reverse()
println reversed  // "olleH"

// Or reassign
text = text.reverse()
println text  // "olleH"

Output

Hello
olleH
olleH

This is the most common mistake. Because strings are immutable, reverse() creates and returns a new string. If you don’t capture the return value, the reversed string is thrown away immediately.

Pitfall 2: Surrogate Pairs and Emojis

Pitfall 2: Surrogate Pairs

// Basic BMP characters work fine
def basic = "ABC"
println basic.reverse()  // CBA

// But characters outside the BMP (emojis, some CJK)
// use surrogate pairs (two Java chars per character)
// Reversing can break them because the pair gets split

// Safe approach for surrogate-pair-aware reversal:
def safeReverse = { str ->
    new StringBuilder(str).reverse().toString()
}
println "Safe reverse: ${safeReverse('ABC')}"

Output

CBA
Safe reverse: CBA

For most strings with standard characters, reverse() works perfectly. But if your strings contain characters outside the Basic Multilingual Plane (certain emojis, rare CJK characters), Java’s StringBuilder.reverse() handles surrogate pairs more carefully. In practice, this only matters if you’re processing user-generated content with emojis.

Pitfall 3: Reversing GStrings

Pitfall 3: GString Reversal

def name = "Groovy"

// GString gets evaluated first, then reversed
def gstring = "Hello ${name}"
println gstring.reverse()        // yvoorG olleH (correct)

// The interpolation happens BEFORE reverse
// reverse() sees "Hello Groovy", not "Hello ${name}"
println gstring.class.name       // org.codehaus.groovy.runtime.GStringImpl
println gstring.reverse().class.name  // java.lang.String

Output

yvoorG olleH
org.codehaus.groovy.runtime.GStringImpl
java.lang.String

When you call reverse() on a GString, Groovy first evaluates the interpolations to produce a plain string, then reverses it. The result is always a java.lang.String, not a GString. This is usually exactly what you want, but it’s good to understand the sequence of operations.

Conclusion

The Groovy string reverse method is a small but mighty tool in your Groovy toolkit. What takes three steps in Java — create a StringBuilder, call reverse, convert back — is a single method call in Groovy. And as we’ve seen across these 10 examples, it’s not just about flipping characters. Palindrome checking, extracting from the end of strings, reversing word order, working with collections, and building real-world utilities like credit card masking and reverse DNS — reverse() is the building block for all of them.

The bottom line is simple: use reverse() and don’t overthink it. It’s fast, it’s readable, and it handles edge cases like empty strings and single characters gracefully. Just remember it’s non-mutating — always assign the result.

For more string manipulation techniques, check out our posts on take() and drop(), which combine beautifully with reverse() for powerful string processing.

Summary

  • reverse() is a GDK method that returns a new string with characters in opposite order
  • It works on both strings and lists — same method name, same behavior
  • It’s non-mutating — always assign the result to a variable
  • Combine with take() and drop() to extract from the end of strings
  • Performance is O(n) and fast enough for virtually all use cases
  • Watch out for surrogate pairs (emojis) — use StringBuilder.reverse() if you need surrogate-aware reversal

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 drop() – Skip First N Characters

Frequently Asked Questions

How do I reverse a string in Groovy?

Call the reverse() method directly on any string: ‘hello’.reverse() returns ‘olleh’. This is a GDK method added to java.lang.String, so it works on any string in Groovy without imports. The method returns a new string and does not modify the original.

Does Groovy reverse() modify the original string?

No. Strings in Groovy (and Java) are immutable. The reverse() method returns a new string with the characters in reverse order. The original string remains unchanged. You must assign the result to a variable: def reversed = myString.reverse().

Can I use reverse() on a list in Groovy?

Yes. Groovy’s reverse() works on both strings and lists. For lists, it returns a new list with elements in the opposite order. For example, [1, 2, 3].reverse() returns [3, 2, 1]. Like with strings, the original list is not modified.

How do I check if a string is a palindrome in Groovy?

Clean the string (remove non-alphanumeric characters, convert to lowercase), then compare it with its reverse. Example: def clean = str.toLowerCase().replaceAll(/[^a-z0-9]/, ''); return clean == clean.reverse(). This handles phrases like ‘A man a plan a canal Panama’.

Is Groovy reverse() safe with Unicode and emojis?

Groovy’s reverse() works correctly with standard Unicode characters (BMP range). However, characters outside the Basic Multilingual Plane (certain emojis, rare scripts) use surrogate pairs in Java, and reversing them can break the pairs. For surrogate-aware reversal, use new StringBuilder(str).reverse().toString() instead.

Previous in Series: Groovy String take() – Get First N Characters

Next in Series: Groovy String drop() – Skip First N Characters

Related Topics You Might Like:

This post is part of the Groovy & Grails Cookbook series on TechnoScripts.com

RahulAuthor posts

Avatar for Rahul

Rahul is a passionate IT professional who loves to sharing his knowledge with others and inspiring them to expand their technical knowledge. Rahul's current objective is to write informative and easy-to-understand articles to help people avoid day-to-day technical issues altogether. Follow Rahul's blog to stay informed on the latest trends in IT and gain insights into how to tackle complex technical issues. Whether you're a beginner or an expert in the field, Rahul's articles are sure to leave you feeling inspired and informed.

No comment

Leave a Reply

Your email address will not be published. Required fields are marked *