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")
}

複雑な式 (complicated expression) の値を補間する場合は、${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()を使用します。これは、文字列を構築するためのロジックをラムダ引数として受け取るインライン関数です。

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

内部では、buildString はJavaと同じ StringBuilder クラスを使用しており、ラムダ内の暗黙的な this を介してそれにアクセスします。

ラムダのコーディング規約について詳しく学ぶ。

コレクションアイテムからの文字列の作成

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では、Kotlinがすべてのリスト (List) に対して定義しているjoinToString()関数を使用します。

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)
}

NOTE

Javaでは、デリミタとそれに続くアイテムの間にスペースを設けたい場合、デリミタに明示的にスペースを追加する必要があります。

joinToString()の使用方法について詳しく学ぶ。

文字列が空白の場合にデフォルト値を設定する

Javaでは、三項演算子 (ternary operator)を使用できます。

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では、例えばデータを難読化 (obfuscate) するために、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では、引数としてデリミタの可変長引数 (varargs) を受け取る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 multiline output

トリプルクォートを最後の単語と同じ行に配置すると、この挙動の違いはなくなります。

Kotlinでは、クォートを新しい行に配置しても出力に余分な空行は追加されません。 任意の行の最も左の文字が行の始まりを識別します。Javaとの違いは、Javaが自動的にインデントをトリムするのに対し、Kotlinでは明示的に行う必要がある点です。

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

出力:

Kotlin multiline output

余分な空行を含めたい場合は、その空行を複数行文字列に明示的に追加する必要があります。

Kotlinでは、インデントをカスタマイズするためにtrimMargin()関数も使用できます。

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

複数行文字列について詳しく学ぶ。

次のステップ

お気に入りのイディオムがある場合は、プルリクエストを送って共有してください。