When we need to transform an iterable into a string, and toString is not enough, we use the joinToString function. In its simplest form, it just presents elements (using their toString method) one after another, separated with commas. However, joinToString is highly customisable with optional arguments:
separator (", " by default) - decides what should be between the values in the produced string.
prefix ("" by default) and postfix ("" by default) - decide what should be at the beginning and at the end of the string. prefix and postfix are also displayed for an empty collection.
limit (-1 by default, which means no limit) and truncated ("..." by default) - limit decides how many elements can be displayed. Once the limit is reached, truncated is shown instead of the rest of the elements.
transform (toString by default) - decides how each element should be transformed to String.
fun main() {
val names = listOf("Maja", "Norbert", "Ola")
println(names.joinToString())
// Maja, Norbert, Ola
println(names.joinToString { it.uppercase() })
// MAJA, NORBERT, OLA
println(names.joinToString(separator = "; "))
// Maja; Norbert; Ola
println(names.joinToString(limit = 2))
// Maja, Norbert, ...
println(names.joinToString(limit = 2, truncated = "etc."))
// Maja, Norbert, etc.
println(names.joinToString(prefix = "{names=[", postfix="]}"))
// {names=[Maja, Norbert, Ola]}
}
Map, Set and String processing
Most of the presented functions are extensions on either Collection or on Iterable, therefore they can be used not only on lists but also on sets. However, in addition to List and Set, there is also the third most important data structure: Map. It does not implement Collection or Iterable, so it needs custom collection processing functions. It has them! Most of the functions we have covered so far are also defined for the Map interface.
The biggest difference between collection and map processing methods stems from the fact that elements in maps are represented by both a key and a value. So, in functional arguments (predicates, transformations, selectors), instead of operating on values we operate on entries (the Map.Entry interface represents both a key and a value). When values are transformed (like in map or flatMap), the result type is List, unless we explicitly transform just keys or values (like in mapValues or mapKeys).
data class User(val id: Int, val name: String)
fun main() {
val names: Map<Int, String> = mapOf(0 to "Alex", 1 to "Ben")
println(names)
// {0=Alex, 1=Ben}
val users: List<User> = names.map { User(it.key, it.value) }
println(users)
// [User(id=0, name=Alex), User(id=1, name=Ben)]
val usersById: Map<Int, User> = users.associateBy { it.id }
println(usersById)
// {0=User(id=0, name=Alex), 1=User(id=1, name=Ben)}
val namesById: Map<Int, String> = usersById
.mapValues { it.value.name }
println(names)
// {0=Alex, 1=Ben}
val usersByName: Map<String, User> = usersById
.mapKeys { it.value.name }
println(usersByName)
// {Alex=User(id=0, name=Alex), Ben=User(id=1, name=Ben)}
}
String is another important type. It is considered a collection of characters, but it does not implement Iterable or Collection. However, to support string processing, most collection processing functions are also implemented for String. However, String also supports many other operations, but these are better explained in the third part of the Kotlin for developers series: Advanced Kotlin.
Marcin Moskala is a highly experienced developer and Kotlin instructor as the founder of Kt. Academy, an official JetBrains partner specializing in Kotlin training, Google Developers Expert, known for his significant contributions to the Kotlin community. Moskala is the author of several widely recognized books, including "Effective Kotlin," "Kotlin Coroutines," "Functional Kotlin," "Advanced Kotlin," "Kotlin Essentials," and "Android Development with Kotlin."
Beyond his literary achievements, Moskala is the author of the largest Medium publication dedicated to Kotlin. As a respected speaker, he has been invited to share his insights at numerous programming conferences, including events such as Droidcon and the prestigious Kotlin Conf, the premier conference dedicated to the Kotlin programming language.
Owen has been developing software since the mid 1990s and remembers the productivity of languages such as Clipper and Borland Delphi.
Since 2001, He moved to Web, Server based Java and the Open Source revolution.
With many years of commercial Java experience, He picked up on Kotlin in early 2015.
After taking detours into Clojure and Scala, like Goldilocks, He thinks Kotlin is just right and tastes the best.
Owen enthusiastically helps Kotlin developers continue to succeed.
Software architect with 15 years of experience, currently working on building infrastructure for AI. I think Kotlin is one of the best programming languages ever created.