Edit Page

Java 和 Kotlin 中的字符串

最终更新: 2024/03/21

这篇向导通过示例程序演示如何在 Java 和 Kotlin 中进行通常的字符串处理. 将会帮助你从 Java 迁移到 Kotlin, 并以 Kotlin 的方式来编写代码.

拼接字符串

在 Java 中, 你可以通过以下方式实现:

// Java
String name = "Joe";
System.out.println("Hello, " + name);
System.out.println("Your name is " + name.length() + " characters long");

在 Kotlin 中, 可以在变量名称之前使用 $ 符号, 将这个变量的值添加到你的字符串之内:

fun main() {
//sampleStart
    // Kotlin
    val name = "Joe"
    println("Hello, $name")
    println("Your name is ${name.length} characters long")
//sampleEnd
}

你可以在字符串内添加复杂表达式的值, 方法是将表达式用括号括起, 比如 ${name.length} . 详情请参见 字符串模板.

构建一个字符串

在 Java 中, 你可以使用 StringBuilder:

// Java
StringBuilder countDown = new StringBuilder();
for (int i = 5; i > 0; i--) {
    countDown.append(i);
    countDown.append("\n");
}
System.out.println(countDown);

在 Kotlin 中, 请使用 buildString() – 一个 内联函数, 参数是一个 Lambda 表达式, 其中包含创建字符串的代码:

fun main() {
//sampleStart
       // Kotlin
       val countDown = buildString {
           for (i in 5 downTo 1) {
               append(i)
               appendLine()
           }
       }
       println(countDown)
//sampleEnd
}

buildString 的内部, 它使用 Java 中相同的 StringBuilder 类, 在 Lambda 表达式 内, 你通过隐含的 this 访问它.

更多详情请参见 Lambda 表达式的编码规约.

通过集合中的元素创建一个字符串

在 Java 中, 你可以使用 Stream API 来过滤, 变换, 并收集元素:

// Java
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);
String invertedOddNumbers = numbers
        .stream()
        .filter(it -> it % 2 != 0)
        .map(it -> -it)
        .map(Object::toString)
        .collect(Collectors.joining("; "));
System.out.println(invertedOddNumbers);

在 Kotlin 中, 请使用 joinToString() 函数, Kotlin 对所有的 List 都定义了这个函数:

fun main() {
//sampleStart
    // Kotlin
    val numbers = listOf(1, 2, 3, 4, 5, 6)
    val invertedOddNumbers = numbers
        .filter { it % 2 != 0 }
        .joinToString(separator = ";") {"${-it}"}
    println(invertedOddNumbers)
//sampleEnd
}

在 Java 中, 如果想要在分隔符与后续元素之间插入空格, 你需要在分隔符中明确的加入空格.

详情请参见 joinToString() 的使用方法.

当字符串为空白时设置默认值

在 Java 中, 你可以使用 三元运算符(Ternary Operator):

// Java
public void defaultValueIfStringIsBlank() {
    String nameValue = getName();
    String name = nameValue.isBlank() ? "John Doe" : nameValue;
    System.out.println(name);
}

public String getName() {
    Random rand = new Random();
    return rand.nextBoolean() ? "" : "David";
}

Kotlin 提供了内联函数 ifBlank(), 它接受一个默认值作为参数:

// Kotlin
import kotlin.random.Random

//sampleStart
fun main() {
    val name = getName().ifBlank { "John Doe" }
    println(name)
}

fun getName(): String =
    if (Random.nextBoolean()) "" else "David"
//sampleEnd

替换一个字符串的最首字符和最末字符

在 Java 中, 你可以使用 replaceAll() 函数. 在这里 replaceAll() 函数接受正规表达式 ^####$, 分别定义以 ## 开始和以 ## 结束的字符串:

// Java
String input = "##place##holder##";
String result = input.replaceAll("^##|##$", "");
System.out.println(result);

在 Kotlin 中, 请使用 removeSurrounding() 函数, 使用 ## 作为:

fun main() {
//sampleStart
    // Kotlin
    val input = "##place##holder##"
    val result = input.removeSurrounding("##")
    println(result)
//sampleEnd
}

查找与替换

在 Java 中, 你可以使用 PatternMatcher 类, 比如, 要混淆某些数据:

// Java
String input = "login: Pokemon5, password: 1q2w3e4r5t";
Pattern pattern = Pattern.compile("\\w*\\d+\\w*");
Matcher matcher = pattern.matcher(input);
String replacementResult = matcher.replaceAll(it -> "xxx");
System.out.println("Initial input: '" + input + "'");
System.out.println("Anonymized input: '" + replacementResult + "'");

在 Kotlin 中, 你可以使用 Regex 类, 它可以简化正规表达式的相关操作. 此外, 可以使用 多行字符串(Multiline String) 来减少反斜杠的数量, 简化正规表达式的书写:

fun main() {
//sampleStart
    // Kotlin
    val regex = Regex("""\w*\d+\w*""") // 多行字符串
    val input = "login: Pokemon5, password: 1q2w3e4r5t"
    val replacementResult = regex.replace(input, replacement = "xxx")
    println("Initial input: '$input'")
    println("Anonymized input: '$replacementResult'")
//sampleEnd
}

字符串切分

在 Java 中, 要使用句号字符 (.)切分一个字符串, 你需要使用转义 (\\). 因为 String 类的 split() 函数接受一个正规表达式作为参数:

// Java
System.out.println(Arrays.toString("Sometimes.text.should.be.split".split("\\.")));

在 Kotlin 中, 请使用 Kotlin 函数 split(), 它接受可变数量的分隔符作为参数:

fun main() {
//sampleStart
    // Kotlin
    println("Sometimes.text.should.be.split".split("."))
//sampleEnd
}

如果你需要使用正规表达式切分字符串, 请使用 split() 函数接受 Regex 作为参数的重载版本.

获取子字符串

在 Java 中, 你可以使用 substring() 函数, 它接受一个起始字符下标作为参数, 从这个位置开始获取子字符串. 要获取这个字符之后的子字符串, 你需要对下标加 1:

// Java
String input = "What is the answer to the Ultimate Question of Life, the Universe, and Everything? 42";
String answer = input.substring(input.indexOf("?") + 1);
System.out.println(answer);

在 Kotlin 中, 请使用 substringAfter() 函数, 想要获取某个字符之后的子字符串时, 不需要计算下标:

fun main() {
//sampleStart
    // Kotlin
    val input = "What is the answer to the Ultimate Question of Life, the Universe, and Everything? 42"
    val answer = input.substringAfter("?")
    println(answer)
//sampleEnd
}

此外, 你还可以获取某个字符最后一次出现位置之后的子字符串:

fun main() {
//sampleStart
    // Kotlin
    val input = "To be, or not to be, that is the question."
    val question = input.substringAfterLast(",")
    println(question)
//sampleEnd
}

使用多行字符串

在 Java 15 之前, 有几种方法创建多行字符串. 比如, 使用 String 类的 join() 函数:

// Java
String lineSeparator = System.getProperty("line.separator");
String result = String.join(lineSeparator,
       "Kotlin",
       "Java");
System.out.println(result);

在 Java 15 中, 有了 文本块(Text Block) 功能. 但需要记住: 如果你打印一个多行字符串, 而且三重引号出现在下一行, 那么会存在一个额外的空行:

// Java
String result = """
    Kotlin
       Java
    """;
System.out.println(result);

输出结果是: Java 15 的多行字符串输出

如果你将三重引号放在最后一个词的同一行, 那么这个差别会消失.

在 Kotlin 中, 你可以对引号放在新行的字符串进行格式化, 输出中不会存在额外的空行. 每行的最左侧字符标识这一行的起始. 与 Java 的区别是, Java 会自动删除缩进字符, 而在 Kotlin 中你需要明确的删除:

fun main() {
//sampleStart
    // Kotlin   
    val result = """
        Kotlin
           Java
    """.trimIndent()
    println(result)
//sampleEnd
}

输出结果是: Kotlin 的多行字符串输出

如果要输出额外的空行, 你需要在你的多行字符串中明确的添加这个空行.

在 Kotlin 中, 你也可以使用 trimMargin() 函数 修改缩进:

// Kotlin
fun main() {
    val result = """
       #  Kotlin
       #  Java
   """.trimMargin("#")
    println(result)
}

详情请参见 多行字符串.

下一步做什么?

如果你有喜欢的惯用法, 欢迎提交一个 pull request, 共享给大家.