Kotlinのwhen文で文字列パターンマッチングを徹底解説!具体例で理解する方法

Kotlinのプログラムにおいて、when文は条件分岐を簡潔かつ強力に記述するための便利なツールです。特に文字列を扱う際、パターンマッチング機能を活用すれば、複雑な条件をシンプルに記述できます。Javaのswitch文に代わる柔軟性を備え、正規表現や複数条件の評価も可能です。

本記事では、Kotlinのwhen文を使用して文字列のパターンマッチングを行う方法について、基礎から応用まで徹底解説します。具体的なコード例や活用事例、エラー処理方法、パフォーマンス最適化まで網羅し、Kotlinプログラミングの効率向上に役立つ知識を提供します。

目次

Kotlinのwhen文の概要


Kotlinのwhen文は、Javaのswitch文に相当する機能ですが、より柔軟で強力な条件分岐が可能です。条件の評価に文字列や数値だけでなく、任意のオブジェクトや範囲、正規表現も使用できます。

基本構文


when文の基本的な構文は以下の通りです。

when (value) {
    "条件1" -> println("条件1に一致")
    "条件2" -> println("条件2に一致")
    else -> println("どの条件にも一致しない")
}

ポイント

  • 任意のデータ型に対応:文字列、数値、ブール値、オブジェクトなどを条件として使用可能です。
  • elseブロック:すべての条件に一致しない場合のデフォルト処理を記述できます。
  • 式としての使用when文は式として使え、値を返すことができます。

簡単な例

val status = "OK"

val message = when (status) {
    "OK" -> "操作が成功しました"
    "ERROR" -> "エラーが発生しました"
    else -> "不明なステータスです"
}

println(message)  // 出力: 操作が成功しました

when文はKotlinのコードをシンプルかつ可読性の高いものにし、複数の条件分岐をスマートに処理するために役立ちます。

文字列パターンマッチングの基礎


Kotlinのwhen文では、文字列のパターンマッチングを簡単に行うことができます。複数の文字列に対して条件を分岐させる際に、冗長なif-else文を使わずにシンプルに記述可能です。

基本的な文字列のパターンマッチング


when文で特定の文字列に一致する条件を判定するには、以下のように記述します。

val command = "start"

when (command) {
    "start" -> println("処理を開始します")
    "stop" -> println("処理を停止します")
    "pause" -> println("処理を一時停止します")
    else -> println("無効なコマンドです")
}

出力結果

処理を開始します

複数の値を一括で判定する


複数の文字列条件を1つのブロックで処理することもできます。

val status = "warning"

when (status) {
    "ok", "success" -> println("成功状態です")
    "error", "failure" -> println("エラーが発生しました")
    "warning" -> println("警告状態です")
    else -> println("不明な状態です")
}

出力結果

警告状態です

大文字・小文字の区別に注意


when文のマッチングはデフォルトで大文字・小文字を区別します。

val input = "HELLO"

when (input) {
    "hello" -> println("小文字のhelloに一致")
    "HELLO" -> println("大文字のHELLOに一致")
    else -> println("どの条件にも一致しません")
}

出力結果

大文字のHELLOに一致

ポイント

  • 複数条件の一括処理が可能。
  • 大文字・小文字の違いに注意する必要がある。
  • else句を使ってデフォルトの処理を記述できる。

これらの基本的なパターンマッチングを活用することで、条件分岐を簡潔に記述できます。

複数の条件を扱う方法


Kotlinのwhen文では、複数の文字列条件をまとめて処理することができます。これにより、同じ処理を複数の条件に適用する場合、コードがシンプルになります。

複数の条件を一括で処理する例


以下の例では、複数の文字列が同じ処理にマッチするように記述しています。

val action = "play"

when (action) {
    "play", "start", "resume" -> println("再生処理を開始します")
    "pause", "stop" -> println("再生処理を停止します")
    else -> println("無効なアクションです")
}

出力結果

再生処理を開始します

条件を組み合わせた複雑な例


条件にさらにロジックを加えて、複数の条件を一度に評価することも可能です。

val command = "shutdown"

when {
    command == "start" || command == "restart" -> println("システムを起動または再起動します")
    command == "stop" || command == "shutdown" -> println("システムを停止します")
    else -> println("不明なコマンドです")
}

出力結果

システムを停止します

in演算子を用いた範囲指定


in演算子を使うことで、文字列の範囲やリストに含まれるかをチェックできます。

val option = "delete"

when (option) {
    in listOf("add", "update", "delete") -> println("データ操作のコマンドです")
    in listOf("start", "stop") -> println("プロセス制御のコマンドです")
    else -> println("不明なオプションです")
}

出力結果

データ操作のコマンドです

ポイント

  • 複数条件を「,」で区切ることで、同じ処理にまとめられます。
  • ||(OR演算子)を使った複合条件も可能です。
  • in演算子でリストや範囲に含まれているかを判定できます。

複数の条件を効果的に処理することで、冗長なコードを避け、可読性が高いプログラムを作成できます。

正規表現を用いたパターンマッチング


Kotlinのwhen文では、正規表現を用いて文字列のパターンマッチングを行うことができます。正規表現を活用することで、柔軟で高度な条件分岐が可能になります。

正規表現によるマッチングの基本


when文内で正規表現を使用する場合は、Regexオブジェクトを使って条件を記述します。以下の例では、正規表現を用いて特定のパターンにマッチするかを確認します。

val input = "hello123"

when {
    input.matches(Regex("hello\\d+")) -> println("helloに続く数字がマッチしました")
    input.matches(Regex("\\d{3}-\\d{4}")) -> println("電話番号の形式にマッチしました")
    else -> println("どのパターンにもマッチしません")
}

出力結果

helloに続く数字がマッチしました

正規表現を使った具体例


以下の例では、入力された文字列がメールアドレスやURLにマッチするかを判定しています。

val input = "user@example.com"

when {
    input.matches(Regex("^[\\w.%+-]+@[\\w.-]+\\.[a-zA-Z]{2,6}$")) -> println("メールアドレスにマッチしました")
    input.matches(Regex("^(https?|ftp)://[\\w.-]+(/\\S*)?$")) -> println("URLにマッチしました")
    else -> println("不明な形式です")
}

出力結果

メールアドレスにマッチしました

複数の正規表現パターンを組み合わせる


複数の正規表現パターンを条件として組み合わせることもできます。

val input = "ABC-1234"

when {
    input.matches(Regex("^[A-Z]{3}-\\d{4}$")) -> println("商品コードにマッチしました")
    input.matches(Regex("^\\d{4}-\\d{2}-\\d{2}$")) -> println("日付形式にマッチしました")
    else -> println("不明なフォーマットです")
}

出力結果

商品コードにマッチしました

ポイント

  • Regexオブジェクトを使って正規表現を記述します。
  • matches関数で文字列が正規表現パターンに一致するか判定します。
  • 複数の正規表現パターンwhen文で組み合わせることで、柔軟な条件分岐が可能です。

正規表現を活用することで、複雑なパターンマッチングもシンプルに実現でき、Kotlinのコードをより強力にすることができます。

パターンマッチングの具体的なコード例


Kotlinのwhen文を使った文字列パターンマッチングの具体的なコード例を紹介します。これらの例を通じて、when文の柔軟な使い方や応用方法を理解しましょう。

1. 基本的なパターンマッチング


入力コマンドに応じて異なる処理を行うシンプルな例です。

fun main() {
    val command = "play"

    when (command) {
        "play" -> println("再生します")
        "pause" -> println("一時停止します")
        "stop" -> println("停止します")
        else -> println("無効なコマンドです")
    }
}

出力結果

再生します

2. 複数条件を一括で処理する例


複数の入力値に対して同じ処理を行う例です。

fun main() {
    val day = "土曜日"

    when (day) {
        "土曜日", "日曜日" -> println("週末です!休みましょう。")
        "月曜日", "火曜日", "水曜日", "木曜日", "金曜日" -> println("平日です。仕事や学校があります。")
        else -> println("無効な曜日です")
    }
}

出力結果

週末です!休みましょう。

3. 正規表現を使ったパターンマッチング


正規表現を使って、入力文字列が特定のパターンにマッチするかを確認する例です。

fun main() {
    val input = "123-4567"

    when {
        input.matches(Regex("\\d{3}-\\d{4}")) -> println("郵便番号の形式です")
        input.matches(Regex("\\d{4}-\\d{2}-\\d{2}")) -> println("日付の形式です")
        else -> println("不明な形式です")
    }
}

出力結果

郵便番号の形式です

4. `in`演算子を使った範囲指定


リストや範囲に含まれているかを判定する例です。

fun main() {
    val fruit = "apple"

    when (fruit) {
        in listOf("apple", "banana", "grape") -> println("これはフルーツです")
        in listOf("carrot", "potato", "spinach") -> println("これは野菜です")
        else -> println("分類できません")
    }
}

出力結果

これはフルーツです

5. 複雑な条件を扱う例


条件にロジックを加えたパターンマッチングの例です。

fun main() {
    val score = 85

    when {
        score >= 90 -> println("成績: 優")
        score in 75..89 -> println("成績: 良")
        score in 60..74 -> println("成績: 可")
        else -> println("成績: 不可")
    }
}

出力結果

成績: 良

ポイント

  • シンプルな文字列比較から正規表現範囲指定まで幅広い条件をサポートします。
  • 条件の記述が柔軟で、複数条件を効率よくまとめられます。
  • when文は式としても使用でき、値を返すことが可能です。

これらのコード例を参考に、Kotlinのwhen文で効率的なパターンマッチングを実践しましょう。

when文でのエラー処理方法


Kotlinのwhen文を使用して条件分岐を行う際、予期しない入力やエラーの可能性がある場合は適切なエラー処理を組み込むことで、プログラムの安定性を向上させることができます。

1. `else`ブロックを活用したエラー処理


when文では、すべての条件にマッチしない場合に備えてelseブロックを設けることで、想定外の入力に対処できます。

fun processCommand(command: String) {
    when (command) {
        "start" -> println("処理を開始します")
        "stop" -> println("処理を停止します")
        "pause" -> println("処理を一時停止します")
        else -> println("エラー: 無効なコマンドです")
    }
}

fun main() {
    processCommand("run")
}

出力結果

エラー: 無効なコマンドです

2. 例外をスローするエラー処理


無効な入力が致命的なエラーである場合、elseブロック内で例外をスローすることができます。

fun processAction(action: String) {
    when (action) {
        "open" -> println("ファイルを開きます")
        "save" -> println("ファイルを保存します")
        else -> throw IllegalArgumentException("エラー: 無効なアクションです")
    }
}

fun main() {
    try {
        processAction("delete")
    } catch (e: IllegalArgumentException) {
        println(e.message)
    }
}

出力結果

エラー: 無効なアクションです

3. `try-catch`ブロックと`when`文の組み合わせ


エラーが予想される処理をtry-catchブロックとwhen文を組み合わせて安全に実行する方法です。

fun parseInput(input: String) {
    try {
        val number = input.toInt()
        when {
            number > 0 -> println("正の数です")
            number < 0 -> println("負の数です")
            else -> println("ゼロです")
        }
    } catch (e: NumberFormatException) {
        println("エラー: 数字を入力してください")
    }
}

fun main() {
    parseInput("abc")
}

出力結果

エラー: 数字を入力してください

4. ログを使ったエラー処理


エラーが発生した際に、システムログに記録することでデバッグや監視に役立てることができます。

import java.util.logging.Logger

fun processStatus(status: String) {
    val logger = Logger.getLogger("StatusLogger")

    when (status) {
        "OK" -> println("システムは正常です")
        "WARN" -> println("警告: 注意が必要です")
        "ERROR" -> {
            println("エラーが発生しました")
            logger.severe("重大なエラーが発生しました: $status")
        }
        else -> logger.warning("不明なステータス: $status")
    }
}

fun main() {
    processStatus("UNKNOWN")
}

出力結果

不明なステータス: UNKNOWN

ポイント

  • elseブロックで予期しない入力に対応する。
  • 例外処理を用いて致命的なエラーを捕捉し、適切な例外をスローする。
  • try-catchブロックwhen文を組み合わせて安全に処理する。
  • ログ出力を活用してエラー情報を記録する。

これらのエラー処理方法を組み合わせることで、Kotlinプログラムの信頼性と保守性を向上させることができます。

パフォーマンスの最適化


Kotlinのwhen文は非常に強力ですが、効率的に使用するためにはいくつかの最適化テクニックを知っておくと便利です。パフォーマンスを向上させる方法や考慮点を解説します。

1. 定数条件を優先的に使用する


when文の条件に定数を使用すると、Kotlinコンパイラは効率的なテーブルジャンプ(ジャンプテーブル)を生成します。これにより、条件分岐が高速になります。

fun processCode(code: Int) {
    when (code) {
        1 -> println("コード1: 処理開始")
        2 -> println("コード2: 処理中")
        3 -> println("コード3: 処理完了")
        else -> println("不明なコードです")
    }
}

ポイント:定数の場合、分岐はO(1)の時間で処理されます。

2. 複数条件のグループ化


複数の条件が同じ処理を行う場合は、条件をグループ化することでコードの冗長性を減らし、パフォーマンスも向上します。

fun processStatus(status: String) {
    when (status) {
        "start", "resume", "run" -> println("処理を開始します")
        "pause", "stop" -> println("処理を停止します")
        else -> println("無効なステータスです")
    }
}

ポイント:条件のグループ化により、比較回数が減少し効率的になります。

3. `in`演算子で範囲やリストを活用する


in演算子を使用して範囲やリストに対するマッチングを効率的に行えます。複数の条件を一度に処理する際に役立ちます。

fun processScore(score: Int) {
    when (score) {
        in 90..100 -> println("成績: 優")
        in 75..89 -> println("成績: 良")
        in 60..74 -> println("成績: 可")
        else -> println("成績: 不可")
    }
}

ポイント:範囲チェックは効率的で、コードがシンプルになります。

4. 頻出パターンを先に記述する


頻繁にマッチする条件はwhen文の最初に記述することで、早期に条件が満たされ、無駄な比較を避けられます。

fun processCommand(command: String) {
    when (command) {
        "play" -> println("再生します")  // 頻出するコマンドを先に記述
        "pause" -> println("一時停止します")
        "stop" -> println("停止します")
        else -> println("無効なコマンドです")
    }
}

ポイント:パフォーマンス向上のため、ヒット率が高い条件を先に記述しましょう。

5. シールクラスを活用する


シールクラス(sealed class)を使うと、when文がすべての条件をカバーしているかコンパイル時にチェックされるため、冗長なelse句を省略できます。

sealed class Command
object Start : Command()
object Stop : Command()
object Pause : Command()

fun handleCommand(command: Command) {
    when (command) {
        is Start -> println("処理を開始します")
        is Stop -> println("処理を停止します")
        is Pause -> println("処理を一時停止します")
    }
}

ポイント:シールクラスを使うと、型安全性が向上し、余分な条件チェックを省けます。

ポイントまとめ

  • 定数条件を使うと高速な分岐が可能。
  • 条件のグループ化で冗長性を減らす。
  • in演算子で範囲やリストを効率的にチェック。
  • 頻出条件を先に記述して比較回数を減らす。
  • シールクラスで型安全性と効率を向上。

これらの最適化テクニックを活用することで、Kotlinのwhen文を効率的に使い、パフォーマンスの良いコードを書くことができます。

応用例:アプリケーションでの活用


Kotlinのwhen文を使った文字列パターンマッチングは、さまざまなアプリケーションで実際に役立ちます。ここでは、いくつかの具体的な応用例を紹介します。

1. チャットボットでのコマンド処理


チャットボットアプリケーションで、ユーザーの入力に基づき異なるアクションを実行する例です。

fun processChatCommand(command: String) {
    when (command.lowercase()) {
        "help" -> println("ヘルプ: 利用可能なコマンドは 'help', 'greet', 'bye' です。")
        "greet" -> println("こんにちは!お元気ですか?")
        "bye" -> println("さようなら!またお会いしましょう。")
        else -> println("エラー: 無効なコマンドです。'help'でコマンド一覧を表示します。")
    }
}

fun main() {
    processChatCommand("greet")
    processChatCommand("HELP")
    processChatCommand("bye")
}

出力結果

こんにちは!お元気ですか?
ヘルプ: 利用可能なコマンドは 'help', 'greet', 'bye' です。
さようなら!またお会いしましょう。

2. Webフォーム入力のバリデーション


Webアプリケーションでユーザーが入力するデータのバリデーションを行う例です。

fun validateInput(input: String) {
    when {
        input.isBlank() -> println("エラー: 入力が空です。")
        input.matches(Regex("^\\d{4}-\\d{2}-\\d{2}$")) -> println("日付形式が正しいです。")
        input.matches(Regex("^[\\w.%+-]+@[\\w.-]+\\.[a-zA-Z]{2,6}$")) -> println("メールアドレス形式が正しいです。")
        else -> println("エラー: 無効な入力です。")
    }
}

fun main() {
    validateInput("2024-06-15")
    validateInput("user@example.com")
    validateInput("")
}

出力結果

日付形式が正しいです。
メールアドレス形式が正しいです。
エラー: 入力が空です。

3. HTTPリクエストの処理


WebアプリケーションでHTTPリクエストのメソッドに応じた処理を行う例です。

fun handleHttpRequest(method: String) {
    when (method.uppercase()) {
        "GET" -> println("データを取得します。")
        "POST" -> println("データを作成します。")
        "PUT" -> println("データを更新します。")
        "DELETE" -> println("データを削除します。")
        else -> println("エラー: 無効なHTTPメソッドです。")
    }
}

fun main() {
    handleHttpRequest("GET")
    handleHttpRequest("POST")
    handleHttpRequest("PATCH")
}

出力結果

データを取得します。
データを作成します。
エラー: 無効なHTTPメソッドです。

4. アプリ内メニューのナビゲーション


モバイルアプリでユーザーがメニューから選択したオプションに応じて画面遷移する例です。

fun navigateMenu(option: String) {
    when (option) {
        "home" -> println("ホーム画面に移動します。")
        "profile" -> println("プロフィール画面に移動します。")
        "settings" -> println("設定画面に移動します。")
        else -> println("エラー: 無効なメニューオプションです。")
    }
}

fun main() {
    navigateMenu("home")
    navigateMenu("settings")
    navigateMenu("logout")
}

出力結果

ホーム画面に移動します。
設定画面に移動します。
エラー: 無効なメニューオプションです。

5. ファイル拡張子に応じた処理


ファイルの拡張子に応じて異なる処理を行う例です。

fun processFile(fileName: String) {
    when {
        fileName.endsWith(".txt") -> println("テキストファイルを処理します。")
        fileName.endsWith(".jpg") || fileName.endsWith(".png") -> println("画像ファイルを処理します。")
        fileName.endsWith(".pdf") -> println("PDFファイルを処理します。")
        else -> println("エラー: 未知のファイル形式です。")
    }
}

fun main() {
    processFile("document.txt")
    processFile("photo.jpg")
    processFile("report.pdf")
    processFile("unknown.xyz")
}

出力結果

テキストファイルを処理します。
画像ファイルを処理します。
PDFファイルを処理します。
エラー: 未知のファイル形式です。

ポイント

  • ユーザー入力の処理データバリデーションに最適。
  • Webアプリケーションモバイルアプリでのナビゲーションにも活用可能。
  • ファイル処理HTTPリクエストの処理など、さまざまなシナリオで効率的な分岐処理が可能。

これらの応用例を参考に、Kotlinのwhen文を実際のアプリケーションに活用して、コードの可読性と効率性を向上させましょう。

まとめ


本記事では、Kotlinのwhen文を使った文字列パターンマッチングについて、基本から応用まで解説しました。when文はシンプルな条件分岐だけでなく、複数条件のグループ化や正規表現を用いた高度なマッチング、エラー処理、パフォーマンス最適化まで柔軟に対応できます。

具体的なコード例やアプリケーションでの活用方法を通じて、when文の有用性と実用的な活用方法を学びました。適切にwhen文を使用することで、Kotlinプログラムの可読性と効率性を大幅に向上させることができます。

今後の開発において、when文を活用し、柔軟でエラーに強いコードを書いていきましょう。

コメント

コメントする

目次