1. 概述

String 是 Kotlin 中最常用的数据类型之一,字符串操作在日常开发中极为频繁。本文将系统介绍几种在 Kotlin 中移除字符串第一个字符的常用方式,并对比它们在边界情况(如空字符串)下的表现。

由于字符串在 Kotlin(以及 Java)中是不可变的(immutable),所谓“移除”实际上是生成一个新字符串对象。这一点无需赘述,相信有经验的读者早已了然于心 ✅。

2. 问题分析

核心目标很明确:给定一个字符串,返回去掉首字符后的新字符串。关键在于处理以下边界情况:

  • 字符串为空(""
  • 字符串只有一个字符

我们将通过单元测试验证每种方法的行为,确保其健壮性。下面进入正题。

3. 使用 drop() 函数 ✅ 推荐

Kotlin 提供了丰富的字符串扩展函数,其中 drop(n) 可以直接丢弃前 n 个字符,非常适合本场景。

val myStr = "0a b c d e"
val result = myStr.drop(1)
assertEquals("a b c d e", result)

优点

  • 语法简洁,语义清晰
  • 对空字符串安全:"".drop(1) 返回空字符串 "",不会抛异常
val result2 = "".drop(1)
assertEquals("", result2) // 正常通过

⚠️ 踩坑提醒:这是最推荐的方式,兼顾简洁与安全性,建议作为首选方案。

4. 使用 substring() 方法 ⚠️ 注意空串

substring(beginIndex) 可以获取从指定索引开始到末尾的子串。要去掉首字符,只需从索引 1 开始截取:

val myStr = "0a b c d e"
val result = myStr.substring(1)
assertEquals("a b c d e", result)

致命缺陷:当输入为空字符串时,substring(1) 会抛出 IndexOutOfBoundsException

assertThrows<IndexOutOfBoundsException> {
    "".substring(1)
}

⚠️ 适用场景:仅当你能100%确保输入非空时才可使用,否则需额外判空,增加代码复杂度。

5. 使用 takeLast() 函数 ❌ 不推荐

takeLast(n) 返回字符串末尾的 n 个字符。因此,可以通过 takeLast(length - 1) 来排除首字符:

val myStr = "0a b c d e"
val result = myStr.takeLast(myStr.length - 1)
assertEquals("a b c d e", result)

你也可以使用 lastIndex 属性替代 length - 1,语义更清晰:

// CharSequence 的扩展属性
public val CharSequence.lastIndex: Int
    get() = this.length - 1

val result = myStr.takeLast(myStr.lastIndex)

严重问题:当字符串为空时,length - 1-1,触发 IllegalArgumentException

val myEmpty = ""
assertThrows<IllegalArgumentException> {
    myEmpty.takeLast(myEmpty.length - 1)
}.also {
    assertEquals("Requested character count -1 is less than zero.", it.message)
}

⚠️ 结论:此方法不够健壮,不推荐用于通用场景。

6. 使用正则 replace() 方法 ✅ 可选方案

利用正则表达式匹配并替换首字符也是一种思路:

val myStr = "0a b c d e"
val result = myStr.replace("^.".toRegex(), "")
assertEquals("a b c d e", result)
  • 正则 ^. 表示匹配行首的任意一个字符
  • 替换为空字符串,即实现“删除”

优势

  • 对空字符串友好:"".replace("^.".toRegex(), "") 返回 ""
  • 不依赖索引,逻辑独立

⚠️ 缺点

  • 性能略低于纯字符串操作(涉及正则引擎)
  • 代码可读性不如 drop(1)

适用场景:适合对性能不敏感且希望统一使用正则处理的项目。

7. 总结

方法 空字符串安全 推荐程度 说明
drop(1) ✅ 是 ⭐⭐⭐⭐⭐ 最佳选择,简洁安全
substring(1) ❌ 否 ⭐⭐ 需额外判空,易踩坑
takeLast(length-1) ❌ 否 边界处理差,不推荐
replace("^.".toRegex(), "") ✅ 是 ⭐⭐⭐⭐ 可用,但略重

最终建议:优先使用 drop(1),它在可读性、安全性和性能之间达到了最佳平衡。

完整示例代码已托管至 GitHub:https://github.com/Baeldung/kotlin-tutorials/tree/master/core-kotlin-modules/core-kotlin-strings-4


原始标题:Remove First Character in String in Kotlin