Kotlin's collection library distinguishes read-only interfaces from their mutable counterparts. List, Set, and Map describe immutable collections, while MutableList, MutableSet, and MutableMap extend them with mutation methods like add, remove, and clear. The standard factories — listOf(), mutableListOf(), setOf(), mutableSetOf(), mapOf(), mutableMapOf(), emptyList(), and emptyList
Functional operations are a hallmark of the library. map transforms each element, filter keeps elements matching a predicate, and reduce aggregates elements starting with the first one — though it throws on empty collections. fold is the safer variant, accepting an explicit initial accumulator that allows empty inputs. mapNotNull applies a transform and discards any null results, while flatMap maps each element to an Iterable and concatenates them into one flat list. groupBy returns a Map keyed by the selector result, and partition splits the collection into a Pair of two lists based on a predicate. For finding elements, firstOrNull returns the first match or null on empty input, while singleOrNull asserts uniqueness by returning null unless exactly one element matches. To convert between collection shapes, list.toSet() or .toHashSet() dedupes into a Set, while keys.zip(values).toMap() builds a map from two parallel lists, and associate or associateWith covers transform-based construction with last-duplicate-key-wins semantics.
Lazy sequences are the eager collection's counterpart. Each operation on a sequence is fused with the next, so elements flow through the chain one at a time without producing intermediate lists — a major advantage for chained operations over large or infinite data. sequenceOf(...), sequence { yield(...); yieldAll(...) }, and asSequence() create a sequence; the sequence builder lets you hand-craft a generator. chunked(size) splits a list into fixed-size batches, useful for pagination or batched network calls, while windowed(size, step, partialWindows) produces overlapping or stepped slices. zip pairs elements from two collections into a List<Pair>, stopping at the shorter one; zipWithNext pairs adjacent elements within a single collection. distinct removes duplicates while preserving first-occurrence order, distinctBy deduplicates by a selected key, sorted and sortedDescending return new lists in ascending or descending natural order, while sortedWith combined with compareBy and thenBy sorts by multiple criteria. reversed() allocates a new list, whereas asReversed() returns a live view that reflects later mutations on a MutableList.
Strings come with rich manipulation tools. String interpolation uses $variable and ${expr}. The substring variants — substring, substringBefore, substringAfter — support both raw indices and delimiter-based extraction. replace supports literal, regex, and range-based replacement, and split accepts an optional limit that caps the number of parts returned. For efficient construction in loops, buildString { append(...) } creates a StringBuilder internally and returns the toString() result, which is preferable to repeated + concatenation; StringBuilder is the underlying type and only worth reaching for directly when reusing instances for performance. isLetterOrDigit, isDigit, isLetter, isUpperCase, and isWhitespace give readable character classification. Multi-line raw strings delimited by triple quotes span multiple lines and skip escape processing (escape a literal $ with \$); trimIndent() and trimMargin() handle indentation. someNullable?.toString() yields null safely for null receivers, and CharSequence is the interface implemented by String, StringBuilder, and StringBuffer — accept it in library functions for flexibility. Regex is constructed with Regex("pattern") or "pattern".toRegex(), used via containsMatchIn, find, findAll, and replace; the find function returns a MatchResult? whose groups you can access via groupValues or destructure with val (user, domain) = match.destructured. Error handling has no checked exceptions: try, catch, and even if are expressions, val n = try { s.toInt() } catch (e: Exception) { -1 } returns an Int. The runCatching { ... } helper wraps a block in try/catch and returns a Result<T>, on which you can chain onSuccess, onFailure, getOrNull, getOrElse, or getOrThrow — but note that runCatching catches Throwable including Error, so prefer typed try/catch for specific exceptions. toIntOrNull() safely converts strings to Int by returning null on parse failure.