Kotlin 字符串
字符串是日常编程用得最多的类型之一——日志、UI 文案、配置文件、网络报文全是字符串。Kotlin 的字符串和 Java 一脉相承(同样不可变,同样基于 UTF-16),但通过字符串模板和丰富的扩展函数大幅提升了表达力。本篇逐个讲。
1. 字符串基础
Kotlin 字符串是 String 类型,用双引号包裹。和 Java/Python 一样,字符串不可变——任何修改都返回新字符串:
// 字符串声明:String 类型,双引号
val s1: String = "hello"
val s2 = "你好,Kotlin"
// 字符串【不可变】:改字符串其实是创建新对象
val original = "abc"
val modified = original.uppercase()
println(original) // abc(原字符串没变)
println(modified) // ABC
// 单个字符:Char,单引号
val c: Char = 'A'
val first = s1[0] // 'h',可以用索引取字符
val len = s1.length // 5单个字符用 Char(单引号),区别于字符串(双引号)。可以用下标访问字符 s[0],但不能赋值(s[0] = 'x' 是错的,因为不可变)。
2. 字符串模板(招牌特性)
这是 Kotlin 比 Java 简洁的核心特性之一——直接在字符串里嵌入变量和表达式:
// 字符串模板:Kotlin 甜点
val name = "小明"
val age = 25
// 简单变量:$ 后跟变量名
val g1 = "你好, $name"
println(g1) // 你好, 小明
// 表达式:用 ${} 包裹
val g2 = "明年 ${age + 1} 岁"
println(g2) // 明年 26 岁
// 调用方法
val g3 = "长度 ${name.length}"
println(g3) // 长度 2
// 嵌套引号:${} 里用双引号
val s = "结果是 ${if (age > 18) "成年" else "未成年"}"
println(s) // 结果是 成年
// 字符串模板大幅减少字符串拼接
// 对比 Java:
// String s = "你好, " + name + "!明年 " + (age+1) + " 岁。"对比 Java 的 "你好, " + name + "!明年 " + (age+1) + " 岁。",Kotlin 的模板直观得多。再也不需要 StringBuilder、String.format 这种啰嗦写法。
3. 原始字符串(Raw String,多行)
用三个双引号 """ 包裹的字符串叫原始字符串,可以跨行、保留缩进、不识别转义符:
// 原始字符串(Raw String):三个引号,保留格式,不转义
val text = """
第一行
第二行
缩进
第三行
"""
println(text)
// 问题:多行字符串常有"缩进污染"(因为代码缩进)
// 用 trimMargin() 去除
val clean = """
|第一行
|第二行
|第三行
""".trimMargin()
// 默认以 | 作为 margin 前缀,删掉每行 | 及之前的空白
// 自定义前缀
val clean2 = """
>第一行
>第二行
""".trimMargin(">")
// 原始字符串【不识别转义符】
val noEscape = """\n 不是换行,是字面的反斜杠 + n"""
println(noEscape)
// 输出: \n 不是换行,是字面的反斜杠 + n原始字符串的常见用途:写 JSON 模板、SQL 查询、HTML 代码、Markdown 文档。配合 trimMargin() 去除代码缩进污染,效果非常干净。
注意原始字符串不识别转义符,所以 \\n 在里面就是字面的反斜杠加 n,要换行就直接换行。但字符串模板仍然有效(\\$var 会被替换)。
4. 基本操作
Kotlin 把所有常用操作做成了 String 的扩展函数,API 设计统一、好记:
// 长度、判空
val s = "Hello"
println(s.length) // 5
println(s.isEmpty()) // false
println(s.isNotEmpty()) // true
val blank = " "
println(blank.isBlank()) // true(只含空白)
println("".isBlank()) // true(空字符串)
// 大小写
println("hello".uppercase()) // HELLO
println("WORLD".lowercase()) // world
// 去除空白
println(" hi ".trim()) // hi
println(" hi ".trimStart()) // hi(右侧保留)
println("xxhiyy".trim('x', 'y')) // hi(去指定字符)
// 子串
val sub = "Hello".substring(1, 4) // ell(闭开区间)
val sub2 = "Hello".take(3) // Hel(前 3 个)
val sub3 = "Hello".takeLast(2) // lo(后 2 个)注意 isEmpty() vs isBlank():前者只检查长度为 0,后者还把"全是空白字符"也算 true。同理 isNotEmpty() vs isNotBlank()。
5. 查找与替换
// 查找
val s = "Hello, World"
println(s.startsWith("Hello")) // true
println(s.endsWith("World")) // true
println(s.contains("World")) // true
println(s.indexOf("o")) // 4(第一个 o 的位置)
println(s.lastIndexOf("o")) // 8(最后一个 o 的位置)
// 替换
val r1 = s.replace("World", "Kotlin")
println(r1) // Hello, Kotlin
// 用正则替换
val r2 = "abc123".replace(Regex("\\d+"), "#")
println(r2) // abc#
// 分割
val parts = "a,b,c".split(",")
println(parts) // [a, b, c]
val csv = "1,2,,3".split(",")
println(csv) // [1, 2, , 3](空字段保留)
// 多分隔符
val mixed = "a,b;c".split(",", ";")
println(mixed) // [a, b, c]注意 split 接受可变参数,可以一次指定多个分隔符。要按正则分割用 split(Regex)。
6. 字符串比较
Kotlin 的字符串比较语义清晰:
// 字符串比较
val a = "hello"
val b = "hello"
val c = "Hello"
// == :【值相等】,调用 equals()
println(a == b) // true
println(a == c) // false(大小写敏感)
// equals 带参数:忽略大小写
println(a.equals(c, ignoreCase = true)) // true
// === :引用相等(通常没必要用)
println(a === b) // 取决于字符串池,通常 true
// compareTo:字典序比较
println("abc".compareTo("abd")) // -1(abc < abd)
println("abc".compareTo("abc")) // 0(相等)
println("abd".compareTo("abc")) // 1(abd > abc)
// 自然顺序排序
val sorted = listOf("banana", "apple", "cherry").sorted()
println(sorted) // [apple, banana, cherry]关键点:== 是值相等(等价 equals),不是 Java 的引用相等。这避免了 Java 初学者最常见的坑:"a" == new String("a") 在 Java 里是 false,但 Kotlin 永远是 true。
7. 字符串构建
当需要拼接大量字符串时,用 buildString 或 StringBuilder(底层就是 Java 的 StringBuilder):
// 重复字符串
val hr = "-".repeat(20)
println(hr) // --------------------
// 字符串数组用 joinToString 拼接
val list = listOf("苹果", "香蕉", "橙子")
val joined = list.joinToString(", ")
println(joined) // 苹果, 香蕉, 橙子
// 自定义前后缀和分隔符
val formatted = list.joinToString(
separator = " | ",
prefix = "[",
postfix = "]"
)
println(formatted) // [苹果 | 香蕉 | 橙子]
// 用 joinTo 拼到 StringBuilder
val sb = StringBuilder()
sb.append("水果: ")
list.joinTo(sb, ", ")
println(sb) // 水果: 苹果, 香蕉, 橙子
// 字符串构建:StringBuilder(用于大量拼接)
val build = buildString {
for (i in 1..5) {
append("行 $i\n")
}
}
println(build)buildString { ... } 是个内联高阶函数,块内 this 是 StringBuilder,适合构建复杂字符串(如 JSON、XML)。比"+"拼接快得多(因为 StringBuilder 是可变的)。
8. 数值与字符串互转
// 字符串转数值
val n1 = "42".toInt() // 42(Int)
val n2 = "3.14".toDouble() // 3.14(Double)
val n3 = "0xFF".toInt(16) // 255(16 进制)
// 安全转换:失败返回 null
val safe: Int? = "abc".toIntOrNull() // null
val safe2: Int? = "42".toIntOrNull() // 42
// 浮点
val d: Double? = "abc".toDoubleOrNull() // null
// 数值转字符串
val s1 = 42.toString() // "42"
val s2 = 3.14.toString() // "3.14"
// 格式化(类似 Java String.format)
val pi = 3.14159265
println("%.2f".format(pi)) // 3.14(保留 2 位)
println("%010.2f".format(pi)) // 0000003.14(0 填充,总宽 10)
// Kotlin 也支持 String.format
val s3 = String.format("%.4f", pi) // 3.1416关键:不要直接 "abc".toInt()(会抛异常),用 toIntOrNull() 安全转换,配合 Elvis 给默认值:val n = s.toIntOrNull() ?: 0。
9. 实战:模板字符串生成报表
data class Score(val name: String, val score: Int)
fun buildReport(scores: List<Score>): String {
val average = if (scores.isEmpty()) 0.0 else scores.map { it.score }.average()
val best = scores.maxByOrNull { it.score }
val worst = scores.minByOrNull { it.score }
return buildString {
appendLine("=== 成绩报表 ===")
appendLine()
// 用 forEach 遍历 + 字符串模板
scores.sortedByDescending { it.score }.forEachIndexed { i, s ->
appendLine("${i + 1}. ${s.name} - ${s.score} 分")
}
appendLine()
appendLine("平均分: ${"%.1f".format(average)}")
appendLine("最高: ${best?.name} ${best?.score} 分")
appendLine("最低: ${worst?.name} ${worst?.score} 分")
}
}
val scores = listOf(
Score("小明", 92),
Score("小红", 88),
Score("小刚", 75)
)
println(buildReport(scores))这个例子综合用了 buildString、字符串模板、可空调用、Elvis、List 扩展函数。一个真实的项目里,字符串处理几乎都是这种模式。
10. 常用 API 速查表
- 长度:
s.length - 判空:
s.isEmpty()s.isBlank() - 大小写:
s.uppercase()s.lowercase() - trim:
s.trim()s.trimStart()s.trimEnd() - 查找:
s.contains()s.startsWith()s.endsWith()s.indexOf() - 替换:
s.replace()s.replaceFirst() - 分割:
s.split() - 子串:
s.substring()s.take()s.takeLast()s.drop() - 比较:
s == ts.equals(t, ignoreCase = true) - 转换:
s.toIntOrNull()s.toDoubleOrNull() - 格式化:
"%.2f".format(pi) - 构建:
buildString { ... }sb.append()list.joinToString() - repeat:
"-".repeat(20)
小结
这一章你掌握了 Kotlin 字符串的所有姿势:模板插值、原始字符串、常用操作、查找替换、比较、构建、数值互转。最大的甜点是字符串模板(告别 Java 的字符串拼接)和原始字符串(优雅写多行文本)。下一篇看 集合——List、Set、Map,Kotlin 集合的 API 极其丰富。
← 上一篇 Kotlin 空安全
下一篇 Kotlin 集合 →