eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

1. Overview

In this tutorial, we’ll take a closer look at the several types of strings in Groovy, including single-quoted, double-quoted, triple-quoted, and slashy strings.

We’ll also explore Groovy’s string support for special characters, multi-line, regex, escaping, and variable interpolation.

2. Enhancing java.lang.String

It’s probably good to begin by stating that since Groovy is based on Java, it has all of Java’s String capabilities like concatenation, the String API, and the inherent benefits of the String constant pool because of that.

Let’s first see how Groovy extends some of these basics.

2.1. String Concatenation

String concatenation is just a combination of two strings:

def first = 'first'
def second = "second"        
def concatenation = first + second
assertEquals('firstsecond', concatenation)

Where Groovy builds on this is with its several other string types, which we’ll take a look at in a moment. Note that we can concatenate each type interchangeably.

2.2. String Interpolation

Now, Java offers some very basic templating through printf, but Groovy goes deeper, offering string interpolation, the process of templating strings with variables:

def name = "Kacper"
def result = "Hello ${name}!"
assertEquals("Hello Kacper!", result.toString())

While Groovy supports concatenation for all its string types, it only provides interpolation for certain types.

2.3. GString

But hidden in this example is a little wrinkle – why are we calling toString()?

Actually, result isn’t of type String, even if it looks like it.

Because the String class is final, Groovy’s string class that supports interpolation, GString, doesn’t subclass it. In other words, for Groovy to provide this enhancement, it has its own string class, GString, which can’t extend from String.

Simply put, if we did:

assertEquals("Hello Kacper!", result)

this invokes assertEquals(Object, Object), and we get:

java.lang.AssertionError: expected: java.lang.String<Hello Kacper!>
  but was: org.codehaus.groovy.runtime.GStringImpl<Hello Kacper!>
Expected :java.lang.String<Hello Kacper!> 
Actual   :org.codehaus.groovy.runtime.GStringImpl<Hello Kacper!>

3. Single-Quoted String

Probably the simplest string in Groovy is one with single quotes:

def example = 'Hello world'

Under the hood, these are just plain old Java Strings, and they come in handy when we need to have quotes inside of our string.

Instead of:

def hardToRead = "Kacper loves \"Lord of the Rings\""

We can easily concatenate one string with another:

def easyToRead = 'Kacper loves "Lord of the Rings"'

Because we can interchange quote types like this, it reduces the need to escape quotes.

4. Triple Single-Quote String

A triple single-quote string is helpful in the context of defining multi-line contents.

For example, let’s say we have some JSON to represent as a string:

{
    "name": "John",
    "age": 20,
    "birthDate": null
}

We don’t need to resort to concatenation and explicit newline characters to represent this.

Instead, let’s use a triple single-quoted string:

def jsonContent = '''
{
    "name": "John",
    "age": 20,
    "birthDate": null
}
'''

Groovy stores this as a simple Java String and adds the needed concatenation and newlines for us.

There is one challenge yet to overcome, though.

Typically for code readability, we indent our code:

def triple = '''
    firstline
    secondline
'''

But triple single-quote strings preserve whitespace. This means that the above string is really:

(newline)
    firstline(newline)
    secondline(newline)

not:

1

2

firstline(newline)

secondline(newline)

like perhaps we intended.

Stay tuned to see how we get rid of them.

4.1. Newline Character

Let’s confirm that our previous string starts with a newline character:

assertTrue(triple.startsWith("\n"))

It’s possible to strip that character. To prevent this, we need to put a single backslash \ as a first and last character:

def triple = '''\
    firstline
    secondline
'''

Now, we at least have:

1

2

firstline(newline)

secondline(newline)

One problem down, one more to go.

4.2. Strip the Code Indentation

Next, let’s take care of the indentation. We want to keep our formatting, but remove unnecessary whitespace characters.

The Groovy String API comes to the rescue!

To remove leading spaces on every line of our string, we can use one of the Groovy default methods, String#stripIndent():

def triple = '''\
    firstline
    secondline'''.stripIndent()
assertEquals("firstline\nsecondline", triple)

Please note, that by moving the ticks up a line, we’ve also removed a trailing newline character. 

4.3. Relative Indentation

We should remember that stripIndent is not called stripWhitespace.

stripIndent determines the amount of indentation from the shortened, non-whitespace line in the string.

So, let’s change the indentation quite a bit for our triple variable:

class TripleSingleQuotedString {

    @Test
    void 'triple single quoted with multiline string with last line with only whitespaces'() {
        def triple = '''\
            firstline
                secondline\
        '''.stripIndent()

        // ... use triple
    }
}

Printing triple would show us:

firstline
    secondline

Since firstline is the least-indented non-whitespace line, it becomes zero-indented with secondline still indented relative to it.

Note also that this time, we are removing the trailing whitespace with a slash, like we saw earlier.

4.4. Strip with stripMargin()

For even more control, we can tell Groovy right where to start the line by using a | and stripMargin:

def triple = '''\
    |firstline
    |secondline'''.stripMargin()

Which would display:

firstline
secondline

The pipe states where that line of the string really starts.

Also, we can pass a Character or CharSequence as an argument to stripMargin with our custom delimiter character.

Great, we got rid of all unnecessary whitespace, and our string contains only what we want!

4.5. Escaping Special Characters

With all the upsides of the triple single-quote string, there is a natural consequence of needing to escape single quotes and backslashes that are part of our string. 

To represent special characters, we also need to escape them with a backslash. The most common special characters are a newline (\n) and tabulation (\t).

For example:

def specialCharacters = '''hello \'John\'. This is backslash - \\ \nSecond line starts here'''

will result in:

hello 'John'. This is backslash - \
Second line starts here

There are a few we need to remember, namely:

  • \t – tabulation
  • \n – newline
  • \b – backspace
  • \r – carriage return
  • \\ – backslash
  • \f – formfeed
  • \’ – single quote

5. Double-Quoted String

While double-quoted strings are also just Java Strings, their special power is interpolation. When a double-quoted string contains interpolation characters, Groovy switches out the Java String for a GString.

5.1. GString and Lazy Evaluation

We can interpolate a double-quoted string by surrounding expressions with ${} or with $ for dotted expressions.

Its evaluation is lazy, though – it won’t be converted to a String until it is passed to a method that requires a String:

def 'String ang GString'() {
    given:
    def string = "example"
    def stringWithExpression = "example${2}"

    expect:
    string instanceof String
    stringWithExpression instanceof GString
    stringWithExpression.toString() instanceof String
}

5.2. Placeholder with Reference to a Variable

The first thing we probably want to do with interpolation is send it a variable reference:

def 'placeholder with variable'() {
    given:
    def name = "John"

    when:
    def helloName = "Hello $name!".toString()

    then:
    helloName == "Hello John!"
}

5.2. Placeholder with an Expression

But, we can also give it expressions:

def 'placeholder with expression'() {
    given:
    def result = "result is ${2 * 2}".toString()

    expect:
    result == "result is 4"
}

We can put even statements into placeholders, but it’s considered as bad practice.

5.3. Placeholders with the Dot Operator

We can even walk object hierarchies in our strings:

def 'placeholder with dotted access'() {
    given:
    def person = [name: 'John']

    when:
    def myNameIs = "I'm $person.name, and you?".toString()

    then:
    myNameIs == "I'm John, and you?"
}

With getters, Groovy can usually infer the property name.

But if we call a method directly, we’ll need to use ${} because of the parentheses:

def 'placeholder with method call'() {
    given:
    def name = 'John'

    when:
    def result = "Uppercase name: ${name.toUpperCase()}".toString()

    then:
    result == "Uppercase name: JOHN"
}

5.4. hashCode in GString and String

Interpolated strings are certainly godsends in comparison to plain java.util.String, but they differ in an important way.

See, Java Strings are immutable, and so calling hashCode on a given string always returns the same value.

But, GString hashcodes can vary since the String representation depends on the interpolated values.

And actually, even for the same resulting string, they won’t have the same hash codes:

def 'GString and String hashcode'() {
    given:
    def string = "2+2 is 4"
    def gstring = "2+2 is ${4}"

    expect:
    string.hashCode() != gstring.hashCode()
}

Thus, we should never use GString as a key in a Map!

6. Triple Double-Quote String

So, we’ve seen triple single-quote strings, and we’ve seen double-quoted strings.

Let’s combine the power of both to get the best of both worlds – multi-line string interpolation:

def name = "John"
def multiLine = """
    I'm $name.
    "This is quotation from 'War and Peace'"
"""

Also, notice that we didn’t have to escape single or double-quotes!

7. Slashy String

Now, let’s say that we are doing something with a regular expression, and we are thus escaping backslashes all over the place:

def pattern = "\\d{1,3}\\s\\w+\\s\\w+\\\\\\w+"

It’s clearly a mess.

To help with this, Groovy supports regex natively via slashy strings:

def pattern = /\d{3}\s\w+\s\w+\\\w+/
assertTrue("3 Blind Mice\Men".matches(pattern))

Slashy strings may be both interpolated and multi-line:

def name = 'John'
def example = /
    Dear ([A-Z]+),
    Love, $name
/

Of course, we have to escape forward slashes:

def pattern = /.*foobar.*\/hello.*/

And we can’t represent an empty string with Slashy String since the compiler understands // as a comment:

// if ('' == //) {
//     println("I can't compile")
// }

8. Dollar-Slashy String

Slashy strings are great, though it’s a bummer to have to escape the forward slash. To avoid additional escaping of a forward slash, we can use a dollar-slashy string. 

Let’s assume that we have a regex pattern: [0-3]+/[0-3]+. It’s a good candidate for dollar-slashy string because in a slashy string, we would have to write: [0-3]+//[0-3]+.

Dollar-slashy strings are multiline GStrings that open with $/ and close with /$. To escape a dollar or forward slash, we can precede it with the dollar sign ($), but it’s not necessary.

We don’t need to escape $ in GString placeholder.

For example:

def name = "John"

def dollarSlashy = $/
    Hello $name!,

    I can show you a $ sign or an escaped dollar sign: $$ 
    Both slashes work: \ or /, but we can still escape it: $/
            
    We have to escape opening and closing delimiters:
    - $$$/  
    - $/$$
 /$

would output:

Hello John!,

I can show you a $ sign or an escaped dollar sign: $ 
Both slashes work: \ or /, but we can still escape it: /

We have to escape opening and closing delimiter:
- $/  
- /$

9. Character

Those familiar with Java have already wondered what Groovy did with characters since it uses single quotes for strings.

Actually, Groovy doesn’t have an explicit character literal.

There are three ways to make a Groovy string an actual character:

  • explicit use of ‘char’ keyword when declaring a variable
  • using ‘as’ operator
  • by casting to ‘char’

Let’s take a look at them all:

def 'character'() {
    given:
    char a = 'A' as char
    char b = 'B' as char
    char c = (char) 'C'

    expect:
    a instanceof Character
    b instanceof Character
    c instanceof Character
}

The first way is very convenient when we want to keep the character as a variable. The other two methods are more interesting when we want to pass a character as an argument to a function.

10. Summary

Obviously, that was a lot, so let’s quickly summarize some key points:

  • strings created with a single quote (‘) do not support interpolation
  • slashy and tripled double-quote strings can be multi-line
  • multi-line strings contain whitespace characters due to code indentation
  • backslash (\) is used to escape special characters in every type, except dollar-slashy string, where we must use dollar ($) to escape

11. Conclusion

In this article, we discussed many ways to create a string in Groovy and its support for multi-lines, interpolation, and regex.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.

And for more information about features of the Groovy language itself, get a good start with our introduction to Groovy Language.

Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)