Start learning free

LESSON 170 OF 348 · STRINGS

Strings in Kotlin: Indexing, Slicing and CharArray

Lesson Read the full explanation

The Java String is an object that represents a sequence of characters, each identified by one index.

Creation:

To create strings in Java, you use double quotes like this:

val greeting = "Hello"

Accessing characters:

To access the characters in a string, you use the .charAt() method

The following example returns the first character of a string with the index zero:

val str = "Hello"
val ch = str[0]
// ch is "H"

Getting the length:

We can get the length of a string using the length() method.

For example, to access the last character of the string, you use the length() - 1 index:

val str = "Hello"
val ch = str[str.length - 1]
// ch is "o"

Concatenating strings via + operator:

To concatenate two or more strings, you use the + operator:

val name = "John"
val str = "Hello " + name

println(str) // prints "Hello John"

If you want to assemble a string piece by piece, you can use the += operator:

var greet = "Welcome"
val name = "John"
greet += " to AlgoCademy, "
greet += name

println(greet) // "Welcome to AlgoCademy, John"

When concatenating many strings, it is recommended to use StringBuilder for performance

String slicing

We often want to get a substring of a string. For this, we use the substring() method.

substring(startIndex, endIndex) returns the substring from startIndex to endIndex:

val str = "JavaScript"
val substr = str.substring(2, 6)

println(substr) // prints "vaSc"

The startIndex is a zero-based index at which the substring() start extraction.

The endIndex is also zero-based index before which the substring() ends the extraction. The substr will not include the character at the endIndex index.

If you omit the endIndex, the substring() extracts to the end of the string:

val str = "JavaScript"
val substr = str.substring(4)

println(substr) // "Script"

String Immutability:

In Java, String values are immutable, which means that they cannot be altered once created.

For example, the following code:

val myStr = "Bob"
myStr[0] = 'J' // compile error!!!

cannot change the value of myStr to "Job", because the contents of myStr cannot be altered.

Note that this does not mean that myStr cannot be changed, just that the individual characters of a string literal cannot be changed. The only way to change myStr would be to assign it with a new string, like this:

var myStr = "Bob"
myStr = "Job"
//or
myStr = 'J' + myStr.substring(1, 3)

Immutability affects performance when concatenating many strings, it is recommended to use StringBuilder for performance

Convert a string to an array of characters:

When we have to change characters often in a string, we want a way of doing this quickly. Because strings are immutable, we change a character by creating a whole new string, which is O(n).

But arrays are mutable and changing an element in an array is O(1). So what we can do is first convert our string to an array of characters, operate on that array and than convert the array back to a string.

We can convert a string to an array using the toCharArray() method like this:

var str = "Andy"
val myArr = str.toCharArray()

// myArr is ['A', 'n', 'd', 'y']
myArr[0] = 'a'
myArr[2] = 'D'

// We convert an array of chars back to a string using the constructor:
str = String(myArr)

println(str) // "anDy"

Iterating through the characters:

We can iterate throught the elements of a string using indices and a for loop like this:

val myStr = "Andy"
for (i in 0 until myStr.length) {
    println(myStr[i])
}

// This will print the characters 'A', 'n', 'd' and 'y' on different lines

This takes O(n) time, where n is the length of the array we iterate on.


Assignment
Follow the Coding Tutorial and let's play with some arrays.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 7
    Ctrl + Enter to check

    KOTLIN · STRINGS

    Strings in Kotlin, explained

    What this lesson covers

    A String in Kotlin is a sequence of characters, each at an index that starts at 0. This lesson shows how to create strings, read characters, measure length, join strings, cut out pieces with substring, and work around the fact that strings can't be edited in place. The exercise at the end combines all of it: it turns "Java" into "TypeScript".

    Creating, indexing and measuring

    val greeting = "Hello"
    val first = greeting[0]                    // 'H'
    val last = greeting[greeting.length - 1]   // 'o'
    println(greeting.length)                   // 5
    

    Square brackets return a Char, not a String, so greeting[0] is 'H' with single quotes. Kotlin has no charAt method: square brackets are the way to read a character. length is a property, so it is written without parentheses. An index outside 0 to length - 1 throws a StringIndexOutOfBoundsException at run time.

    Joining strings

    The + operator joins two strings into a new one, and += joins and stores the result back in a var:

    val name = "John"
    val str = "Hello " + name
    println(str)          // Hello John
    
    var greet = "Welcome"
    greet += " to the course, "
    greet += name
    println(greet)        // Welcome to the course, John
    

    Both forms copy the existing text into a fresh string. A few joins cost nothing noticeable, but a loop that appends thousands of times copies more and more text on every pass. For that case use a StringBuilder, which grows in place, and call toString() at the end.

    Slicing with substring

    substring(startIndex, endIndex) returns the characters from startIndex up to, but not including, endIndex. With one argument it runs to the end of the string.

    val str = "JavaScript"
    println(str.substring(2, 6)) // vaSc
    println(str.substring(4))    // Script
    

    The result has endIndex - startIndex characters. Both indexes must lie between 0 and length; "Hello".substring(3, 9) throws a StringIndexOutOfBoundsException.

    Strings are immutable

    No operation changes a String after it is created. Assigning to a character is a compile error:

    val myStr = "Bob"
    myStr[0] = 'J' // error: no 'set' operator method providing array access.
    

    The only way to "change" text is to build a new string and store it in a var:

    var myStr = "Bob"
    myStr = "Job"
    myStr = "J" + myStr.substring(1)  // Job again, built from pieces
    

    When you join a single Char and a String, put the Char first and the string second ('J' + "ob"), or convert it with toString(). Writing "ob" + 'J' also works, and gives "obJ".

    Changing characters with a CharArray

    Replacing one character by building a whole new string takes O(n) time. If you need many changes, copy the characters into a CharArray, whose elements can be assigned in O(1), edit it, and convert it back:

    var str = "Andy"
    val myArr = str.toCharArray()   // ['A', 'n', 'd', 'y']
    myArr[0] = 'a'
    myArr[2] = 'D'
    str = String(myArr)
    println(str)                    // anDy
    

    toCharArray() makes a copy, so the original string is untouched. String(myArr) builds a new string from the array. Note that myArr is a val and can still change its elements: val fixes which array the variable points to, not what is inside it.

    Looping over characters

    val myStr = "Andy"
    for (i in 0 until myStr.length) {
        println(myStr[i])
    }
    

    This prints A, n, d and y on separate lines. 0 until myStr.length excludes the upper bound, so the last index used is length - 1. When the index itself isn't needed, for (c in myStr) is shorter. Either way the loop takes O(n) time.

    The exercise, step by step

    1. Create lang as a var. It starts as "Java" and gets reassigned in the next step, so val would not compile.
    2. Append with +=. lang += "script" builds "Javascript" and stores it in lang.
    3. Cut the tail. lang.substring(4) starts at index 4, the s, and runs to the end, giving "script". A val is enough because it is never reassigned.
    4. Join a new prefix. "Type" + substr gives "Typescript", stored in a var named newLang because step 7 reassigns it.
    5. Copy into an array. newLang.toCharArray() gives the mutable copy that the capital letter will be written into.
    6. Edit index 4. The characters of "Typescript" are T, y, p, e, s, so the lower-case s is at index 4. Assign 'S' with single quotes, because the array holds Char values.
    7. Build the string back. String(charArray) is assigned to newLang, which now holds "TypeScript".
    var lang = "Java"
    lang += "script"
    val substr = lang.substring(4)
    var newLang = "Type" + substr
    val charArray = newLang.toCharArray()
    charArray[4] = 'S'
    newLang = String(charArray)
    

    Common mistakes

    • Using double quotes for a character. charArray[4] = "S" is a type mismatch: a String is not a Char.
    • Declaring a variable with val and then reassigning it. The compiler reports that a val cannot be reassigned.
    • Off-by-one in substring. The end index is excluded, and the start index is included.
    • Expecting toCharArray() to change the string. It returns a separate copy.

    Key takeaways

    • Index with str[i], measure with str.length, slice with substring.
    • Strings are immutable; build a new one and store it in a var.
    • For many edits, use a CharArray and String(array); for many joins, use a StringBuilder.
    Keep going with KotlinAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free