1. Introduction
One feature that differentiates Kotlin Language from its Java counterpart is the concept of extension functions. They are a way of adding functionality to a class without extending the class. By adding functionality, we mean creating new methods for a class and using them as bona fide methods of that class.
This tutorial will focus on some common extension functions that come readily available in Kotlin for the String class.
2. When to Use Them
In addition to knowing what extension functions are, it is equally important to know when to use them.
Most importantly, we use this concept in cases where we would love to add functionality to a class that we can’t modify.
For example, suppose we want to get the cube of an Int variable in our code and then later notice that we might need to perform this operation a couple of times. Since the Int class does not provide any built-in function to accomplish this requirement, and we can’t modify the Int class, we can elect to use an extension function on the Int class that can perform this requirement for us on any Int.
We already have an interesting tutorial on this topic that provides more details and depth on extension functions.
3. Common Extension Function for String Class in Kotlin
The String class in Kotlin comes with a huge number of extension functions. As a result, we shall go over a couple in this article – those that are commonly used.
It is important to note that these functions can be used directly on a String object in Kotlin.
3.1. replace()
String.replace() has two variants. They differ in the type of parameters they accept:
fun String.replace(
oldChar: Char,
newChar: Char,
ignoreCase: Boolean = false
): String
This one accepts character parameters as shown in the code above. It returns a new string with all the occurrences of the oldChar replaced with newChar.
The ignoreCase parameter is false by default. If set to true then it will ignore case while handling the replacement. This means that an oldChar = ‘a’ will match ‘a’ or ‘A’:
val inputString0 = "Jelly"
assertEquals("Jezzy", inputString0.replace('l', 'z'))
assertEquals("Pelly", inputString0.replace('j', 'P', true))
assertEquals("Jelly", inputString0.replace('j', 'P'))
fun String.replace(
oldValue: String,
newValue: String,
ignoreCase: Boolean = false
): String
Here, we see another variant that accepts String parameters and acts similarly to the variant we just discussed above:
val inputString1 = "Kotlin Replace Program"
assertEquals("Kotlin Replace Examples", inputString1.replace("PROGRAM", "Examples", true))
3.2. uppercase()
The uppercase() function has the following construct:
fun String.uppercase(): String
It returns a new string with all the characters in the calling string converted to uppercase:
var str = "Extension Functions"
var result = str.uppercase()
assertEquals("EXTENSION FUNCTIONS", result)
3.3. lowercase()
lowercase() is another function that works in an opposite but similar way to the uppercase function:
fun String.lowercase(): String
Similarly, it returns a new string except that with this function, all the characters in the calling string are converted to lowercase:
var str = "Extension Functions"
var result = str.lowercase()
assertEquals("extension functions", result)
3.4. toCharArray()
String.toCharArray() converts a string to an array of characters:
fun String.toCharArray(): CharArray
It returns a character array constituting the characters of the calling string:
val str = "functions"
val chars = str.toCharArray()
val convertedString = String(chars)
assertEquals("functions", convertedString)
3.5. substring()
The substring() method has two variants that differ in the number of parameters they accept :
fun String.substring(startIndex: Int): String
This variant returns a substring of the string starting at the index position specified by startIndex parameter and continues to the end of the string:
val str1 = "Hello World"
val substring1 = str1.subString(6)
assertEquals("World", substring1)
fun String.substring(startIndex: Int, endIndex: Int): String
The second variant of this function accepts two parameters, startIndex, and endIndex. It returns a substring of the calling string starting at the index position specified by startIndex and continues to the index position specified by endIndex – 1:
val str1 = "Hello World"
val substring2 = str1.subString(0, 5)
assertEquals("Hello", substring2)
3.6. startsWith()
Similarly, the startsWith() method has two variations. The difference in these variations lies in the number of parameters passed. While one variation accepts two parameters, the other accepts three. However, for each variation, the boolean parameter ignoreCase is optional and false by default.
Let’s look at the first one:
fun String.startsWith(
prefix: String,
ignoreCase: Boolean = false
): Boolean
This variant returns true if the string starts with the specified prefix:
val str = "extensionfunctions"
assertTrue(str.startsWith("ext"))
Now, let’s look at the second variant:
fun String.startsWith(
prefix: String,
startIndex: Int,
ignoreCase: Boolean = false
): Boolean
This variant returns true if the substring of the string starting at the startIndex position begins with the prefix specified:
val str = "extensionfunctions"
assertTrue(str.startsWith("fun", 9))
3.7. endsWith()
Contrarily, endsWith() returns true if the calling string ends with the characters specified in suffix:
fun String.endsWith(
suffix: String,
ignoreCase: Boolean = false
): Boolean
val str = "Kotlin"
assertTrue(str.endsWith("lin"))
3.8. compareTo()
Another interesting function is the compareTo() function. It is used to compare two strings and accepts one string parameter other as seen in the function definition:
fun compareTo(other: String): Int
String.compareTo() returns an int value:
- Returns 0 if the calling string is equal to the string specified by the other parameter
- Returns a positive int if the calling string has an ASCII value greater than that of the string specified by the other parameter
- Returns a negative int if the calling string has an ASCII value smaller than that of the string specified by the other parameter
var str1 = "Hello"
var str2 = "Hello"
assertTrue(str1.compareTo(str2) == 0)
str2 = "Hallo"
assertTrue(str1.compareTo(str2) > 0)
assertTrue(str2.compareTo(str2, str1) < 0)
3.9. toByteArray()
This function converts a String into its Byte Array equivalent:
fun String.toByteArray(
charset: Charset = Charsets.UTF_8
): ByteArray
It returns a ByteArray created from the characters of the calling string:
val str = "Hello"
val byteArray = str.toByteArray()
assertEquals("[72,101,108,108,111]", byteArray.contentToString())
3.10. capitalize()
String.capitalize() returns a copy of the calling string, having its first letter upper-cased:
fun String.capitalize(): String
It returns the original string if the calling string is empty or already starts with an upper-case letter:
var str = "kotlin functions"
assertEquals("Kotlin functions", str.capitalize())
4. Conclusion
Extension functions empower programmers with the ability to extend the functionality of a class without having to modify it.
Most importantly, we’ve looked at several extension functions that are readily available for String objects in Kotlin. Additionally, we have demonstrated their usage with concrete code examples.
We have code samples and relevant test cases pertaining to this tutorial over on GitHub.