Skip to content

Java 与 Kotlin 中的字符串

本指南包含在 Java 和 Kotlin 中执行典型字符串任务的示例。它将帮助您从 Java 迁移到 Kotlin,并以地道的 Kotlin 方式编写代码。

串联字符串

在 Java 中,您可以按以下方式执行此操作:

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

在 Kotlin 中,在变量名前使用美元符号 ($) 即可将该变量的值插值到您的字符串中:

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

您可以通过用花括号括起复杂的表达式来对其值进行插值,如 ${name.length}。 有关更多信息,请参阅字符串模板

构建字符串

在 Java 中,您可以使用 StringBuilder

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

在 Kotlin 中,使用 buildString() —— 这是一个内联函数,它接收用于构造字符串的逻辑作为 lambda 表达式实参:

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

在底层,buildString 使用与 Java 相同的 StringBuilder 类,您可以在 lambda表达式 内部通过隐式的 this 访问它。

详细了解 lambda表达式 编码约定

从集合项创建字符串

在 Java 中,您可以使用 Stream API 来筛选、映射并收集这些项:

java
// 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 都定义了该函数:

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

在 Java 中,如果您希望在分隔符与后续项之间留有空格,则需要显式地向分隔符添加空格。

详细了解 joinToString() 用法。

如果字符串为空白则设置默认值

在 Java 中,您可以使用三元运算符

java
// 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
// Kotlin
import kotlin.random.Random

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

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

替换字符串开头和结尾的字符

在 Java 中,您可以使用 replaceAll() 函数。 在此示例中,replaceAll() 函数接受正则表达式 ^####$,它们分别定义了以 ## 开头和结尾的字符串:

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

在 Kotlin 中,使用 removeSurrounding() 函数并指定字符串分隔符 ##

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

替换出现的内容

在 Java 中,您可以使用 PatternMatcher 类,例如用于脱敏某些数据:

java
// 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 类,它简化了正则表达式的使用。 此外,使用多行字符串可以通过减少反斜杠的数量来简化正则表达式模式:

kotlin
fun main() {
    // Kotlin
    val regex = Regex("""\w*\d+\w*""") // multiline string
    val input = "login: Pokemon5, password: 1q2w3e4r5t"
    val replacementResult = regex.replace(input, replacement = "xxx")
    println("Initial input: '$input'")
    println("Anonymized input: '$replacementResult'")
}

拆分字符串

在 Java 中,要使用点字符 (.) 拆分字符串,您需要使用转义 (\\)。 这是因为 String 类的 split() 函数接受正则表达式作为实参:

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

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

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

如果您需要使用正则表达式进行拆分,请使用接受 Regex 作为参数的 split() 重载版本。

获取子字符串

在 Java 中,您可以使用 substring() 函数,它接受要开始获取子字符串的字符的包含起始索引。 要获取该字符之后的子字符串,您需要增加索引:

java
// 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() 函数,无需计算您想要获取其后子字符串的字符索引:

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

此外,您可以获取字符最后一次出现之后的子字符串:

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

使用多行字符串

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

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

在 Java 15 中,出现了文本块。 有一点需要记住:如果您打印一个多行字符串,且三引号位于下一行,则会多出一个空行:

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

输出结果:

Java 15 多行输出

如果您将三引号放在与最后一个单词相同的行上,这种行为差异就会消失。

在 Kotlin 中,您可以将引号放在新行来格式化代码行,输出中不会有多余的空行。任何一行的最左侧字符都标识该行的开始。与 Java 的区别在于,Java 会自动修剪缩进,而在 Kotlin 中您应该显式地执行此操作:

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

输出结果:

Kotlin 多行输出

要获得额外的空行,您应该显式地向多行字符串添加该空行。

在 Kotlin 中,您还可以使用 trimMargin() 函数来自定义缩进:

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

详细了解多行字符串

下一步?

如果您有喜爱的惯用法,欢迎通过发送拉取请求来分享。