1. Overview

In this tutorial, we’ll explain what Kotlin’s String templates are and how to use them.

In order to get familiar with other features and to know how to use Kotlin, have a look at one of our Kotlin tutorials.

2. Strings in Kotlin

Like in Java, Strings in Kotlin are immutable. That means that we have no means to alter a String once it’s created. However, we may derive another String from a given one.

Kotlin has enriched the Java String class with additional functionality.

For example, the method padEnd() allows us to format a String, so that the expression:

"Hello".padEnd(10, '!')

Which produces a new string “Hello!!!!!”.

3. String Templates

String templates are String literals that contain embedded expressions.

For example, this code in Java:

String message = "n = " + n;

In Kotlin is just:

val message = "n = $n"

Any valid Kotlin expression may be used in a String template:

val message = "n + 1 = ${n + 1}"

Unlike Java, many of Kotlin’s constructs (but certainly, not all) are expressions.

Therefore, a String template may contain logic as well:

val message = "$n is ${if(n > 0) "positive" else "not positive"}

Notice that inside the curly brackets there’s a valid Kotlin expression. This is a reason why we don’t escape the nested double-quotes.

String templates are resolved by evaluating the expression and invoking a toString() method on the result of the evaluation.

String templates can be nested:

val message = "$n is ${if (n > 0) "positive" else 
  if (n < 0) "negative and ${if (n % 2 == 0) "even" else "odd"}" else "zero"}"

The String template parser starts to resolve it from the most nested template, evaluates it, and invokes a toString() method on it.

Though the String templates may be nested, it’s a good idea to have them as simple as possible. This isn’t difficult at all because Kotlin provides us with many useful tools.

What if we want to use a raw dollar sign and not as a part of a String template?

Then we escape it by putting a backslash in front of it:

val message = "n = \$n"

What follows the dollar sign becomes a usual String – it isn’t evaluated anymore and it is interpreted as is.

4. Raw Strings

In Kotlin, additionally, we have triple-quoted raw Strings that can contain special characters without the need for escaping them.

The resulting String is contained between two consecutive non-overlapping occurrences of triple double-quote-signs .

For example, in Java, in order to create properly a String containing a Windows-style file path to a resource located at C:\Repository\read.me, we should define it in this way:

String path = "C:\\Repository\\read.me"

In Kotlin, we may use the triple-quoted notation in order to achieve the same result:

val path = """C:\Repository\read.me"""

We may use this notation in order to create a multi-line String:

val receipt = """Item 1: $1.00
Item 2: $0.50"""

Which creates a String that spans exactly two lines. If we prefer this indentation:

val receipt = """Item 1: $1.00
                >Item 2: $0.50""".trimMargin(">")

We use a trimMargin() method that eliminates eventual white spaces from the start of every line up to the first occurrence of the margin prefix (> in the example above).

Triple-quoted strings don’t support any escape sequences. It means that if we wrote

val receipt = """Item 1: $1.00\nItem 2: $0.50"""

in order to get a two-line String, we’d get a single line containing the characters \n instead of the expected line break.

Triple-quoted Strings do support templating though. 

It means that any sequence starting with the dollar sign gets resolved to a string in a way as we have described in the previous section. We may use this fact in order to make the escape characters work:

val receipt = """Item 1: $1.00${"\n"}Item 2: $0.50"""

5. Using Dollar Sign in Multiline String

In this section, we’ll learn how to use a dollar sign in a multiline string. Since raw strings are more readable for keeping multiline string values, we’ll use them as a preferred choice over double-quoted strings.

5.1. Understanding the Scenario

Let’s say we’re working with MongoDB queries in our Kotlin application. Furthermore, we want to  query the people collection for folks who are 18 years or older:

db.people.find(
  {
    "age": { $gte: 18 }
  }
)

We can notice that our query is a multiline string with a dollar sign in the $gte operator.

Let’s start by seeing if we can store this query as it is within the findAdultsQuery raw string:

val findAdultsQuery = """
db.people.find(
  {
    "age": { $gte: 18 }
  }
)
"""

Unfortunately, we get a compilation error because Kotlin tries to interpolate $gte as a Kotlin variable, which isn’t defined.

Now, let’s check if we can escape the dollar sign and use it within the findAdultsQuery raw string:

val findAdultsQuery = """
db.people.find(
  {
    "age": { \$gte: 18 }
  }
)
"""

Tough luck again! We get a compilation error because Kotlin doesn’t support escaping the special characters within the raw string.

So, let’s explore a few ways to solve this problem of using a dollar sign in a multiline string.

5.2. Using String Interpolation With Literals

If we want to use a dollar sign within a raw string, the best practice is to use ${‘$’}. In this approach, Kotlin uses string interpolation using ${} with the dollar sign as a literal character (‘$’).

Let’s use this approach to define the findAdultsQuery raw string:

val dollarChar = "$"
val findAdultsQuery = """
db.people.find(
  {
    "age": { ${'$'}gte: 18 }
  }
)
"""
assertTrue(dollarChar in findAdultsQuery)

Fantastic! It looks like we’ve nailed this one.

Moreover, we must note that this approach also works for double-quoted multiline strings with the newline characters (\n).

So, let’s verify this by defining the findAdultsQuery string as a double-quoted string:

val dollarChar = "$"
val findAdultsQuery = "db.people.find(\n{\n\"age\": { ${'$'}gte: 18 }\n }\n)"
assertTrue(dollarChar in findAdultsQuery)

It works as expected.

5.3. Alternatives Approach

Alternatively, we can use more flexible double-quoted strings to escape special characters with a backslash character (*\*).

Let’s implement this approach and confirm that it works as expected:

val dollarChar = "$"
val findAdultsQuery = "db.people.find(\n{\n\"age\": { \$gte: 18 }\n }\n)"
assertTrue(dollarChar in findAdultsQuery)

Great! We got this one right.

6. Conclusion

In this article, we’ve considered one feature of the Kotlin language that is absent in Java – String templates. We’ve illustrated their usage in the case of usual and multi-line Strings.

As always, the source code for the examples is available over on GitHub.


« 上一篇: Kotlin与Ktor
» 下一篇: 在Kotlin中使用枚举