Kotlinでwhen式を使いこなすたった15の方法

Kotlinでwhen式をマスターするための15の方法 Kotlin

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

このサービスはSSPによる協力の下、運営されています。

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

プログラミングにおいて、条件分岐は避けて通れない大切な部分ですよね。

特に、Kotlinを使い始めたばかりの方々にとって、when式はその力強い味方。

この記事を読めば、Kotlinのwhen式を使いこなすことができるようになります。

例えば、ある変数が特定の条件を満たすかどうかで処理を分岐したい場合、if-else文だけでは煩雑になりがちです。

そこでwhen式が役立ちます。

●Kotlinのwhen式とは

○when式の基本

when式はKotlinにおける強力な条件分岐の構文です。

基本的な形は次のようになります。

when (条件変数) {
    値1 -> {
        // 値1に一致する場合の処理
    }
    値2 -> {
        // 値2に一致する場合の処理
    }
    else -> {
        // どの値にも一致しない場合の処理
    }
}

このコードでは、条件変数という変数が値1値2か、それ以外かを判定し、それぞれのケースで異なる処理を行っています。

○when式とは何か

when式はJavaやC言語のswitch文に似ていますが、より柔軟性があります。

例えば、Kotlinのwhen式では、整数だけでなく文字列やオブジェクトなども条件として使えます。

○when式の用途

when式は次のような場合に特に有用です。

  1. 多数の値によって処理を分岐したいとき
  2. 範囲や型で条件を指定したいとき
  3. 複雑な条件式を簡潔に書きたいとき

●when式の詳細な使い方

Kotlinのwhen式を使いこなすためには、実践的な例に触れることが重要です。

ここでは、多角的にwhen式を解説し、具体的なサンプルコードを交えながらその使い方をご紹介します。

○サンプルコード1:整数値を判定する基本的なwhen式

最も基本的な形でのwhen式の使用方法を紹介します。

この例では整数値の変数xを条件としています。

fun main() {
    val x = 3
    when (x) {
        1 -> println("x is 1")
        2 -> println("x is 2")
        3 -> println("x is 3")
        else -> println("x is unknown")
    }
}

このコードは整数値のxが1, 2, 3のいずれかに一致するかどうかを判定しています。

一致する場合はその値に応じたメッセージを出力し、どれにも一致しない場合は”unknown”と出力します。

実行すると”x is 3″と表示されます。

それは変数xが3で、when式の条件と一致したためです。

○サンプルコード2:文字列を判定するwhen式

when式は整数だけでなく、文字列に対しても使用することができます。

次の例では、文字列fruitが何であるかを判定しています。

fun main() {
    val fruit = "Apple"
    when (fruit) {
        "Apple" -> println("It's an apple.")
        "Banana" -> println("It's a banana.")
        "Cherry" -> println("It's a cherry.")
        else -> println("I don't know what it is.")
    }
}

このコードは変数fruitが”Apple”, “Banana”, “Cherry”のいずれかと一致するかどうかを判定しています。

一致する場合はそのフルーツ名に応じたメッセージを出力し、どれにも一致しない場合は”I don’t know what it is.”と出力します。

実行すると”It’s an apple.”と表示されます。

それは変数fruitが”Apple”で、when式の条件と一致したからです。

○サンプルコード3:複数の条件をまとめる

Kotlinのwhen式では、複数の条件を同一の処理でまとめることが可能です。

ここではその手法について解説します。

fun main() {
    val score = 85
    when(score) {
        90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100 -> println("優秀")
        80, 81, 82, 83, 84, 85, 86, 87, 88, 89 -> println("良い")
        else -> println("その他")
    }
}

このコードでは、scoreという整数型の変数に対して、複数の値が一致する場合に同一の処理を行っています。

たとえば、scoreが80から89のいずれかの値であれば”良い”と出力されます。

このプログラムを実行すると”良い”と表示されます。変数scoreの値が85であり、80から89の範囲に一致するためです。

○サンプルコード4:条件式を使用する

when式では条件式も利用できます。

次の例ではageという変数が特定の条件に合致するかを判定しています。

fun main() {
    val age = 25
    when {
        age >= 20 && age < 30 -> println("20代")
        age >= 30 && age < 40 -> println("30代")
        else -> println("それ以外")
    }
}

このサンプルコードではage変数が特定の範囲内にあるかどうかを条件式で評価しています。

具体的には、ageが20以上30未満であれば”20代”と出力、30以上40未満であれば”30代”と出力しています。

このプログラムを実行すると”20代”と表示されるはずです。

それは変数ageが25であり、20以上30未満の範囲に合致しているためです。

○サンプルコード5:変数に結果を代入する

Kotlinでのwhen式の使い方として、条件に応じた値を直接変数に代入するケースも非常に有用です。

これを活用すると、コードがすっきりと整理され、読みやすくなります。

具体的なサンプルコードを紹介します。

fun main() {
    val score = 88
    val grade = when (score) {
        in 90..100 -> "優秀"
        in 80..89 -> "良い"
        in 70..79 -> "可"
        else -> "不可"
    }
    println("あなたの成績は$grade です。")
}

このサンプルコードでは、when式を使ってgradeという変数に文字列を代入しています。

scoreという変数の値によって、”優秀”、”良い”、”可”、”不可”のいずれかがgradeに代入される仕組みです。

Kotlinではinを使って数値の範囲を簡単に指定できるため、このようなケースで非常に便利です。

このコードを実行すると、コンソールには「あなたの成績は良い です。」と表示されます。

それは、score変数の値が88であり、80から89の範囲に合致するためです。

○サンプルコード6:is演算子とwhen式を組み合わせる

Kotlinでは、is演算子を用いてオブジェクトが特定の型に属するかどうかを判定することができます。

when式とis演算子を組み合わせれば、より複雑な型判定が容易になります。

下記のコードを参照してください。

fun main() {
    val obj: Any = "This is a String"
    val result = when (obj) {
        is String -> "文字列です。"
        is Int -> "整数です。"
        else -> "その他の型です。"
    }
    println("このオブジェクトは$result")
}

このサンプルコードでは、objという変数がAny型で定義されていますが、when式とis演算子を使ってその型を判定し、result変数に判定結果を文字列として代入しています。

コードを実行した場合、出力結果は「このオブジェクトは文字列です。」となります。

変数objに格納されているオブジェクトがString型であるため、当然ながらis Stringの条件が真となり、”文字列です。”がresultに代入されています。

○サンプルコード7:範囲を指定して判定する

when式の魅力の一つは、非常に柔軟な条件を設定できることです。

その柔軟性を活かす具体例として、範囲を指定して判定を行うケースがあります。

これは主に数値の範囲を指定する場合に非常に役立ちます。

fun main() {
    val temperature = 25
    val weather = when (temperature) {
        in -5..0 -> "極寒"
        in 1..10 -> "寒い"
        in 11..20 -> "肌寒い"
        in 21..30 -> "快適"
        else -> "暑い"
    }
    println("現在の気温は$temperature℃で、$weather です。")
}

このコードでは、温度(temperature変数)に応じてその日の天気(weather変数)を判定しています。

inキーワードを使い、温度が特定の範囲に含まれる場合に対応する天気の文字列がweatherに代入されます。

ここでの範囲は、例えばin -5..0とすることで、-5から0までの数値が含まれることを意味します。

このコードを実行したとき、temperatureは25であるため、weatherには”快適”が代入され、最終的な出力は「現在の気温は25℃で、快適 です。」となります。

●when式の応用例

Kotlinのwhen式は、非常に多様な条件判定が可能ですが、基本的な使い方を超えて、更に多角的なケースに対応する応用例も存在します。

今回は、enumや関数の引数としてwhen式を使用する場合の応用例について詳しく解説します。

○サンプルコード8:when式でenumを扱う

enum(列挙型)もwhen式で簡単に扱うことができます。

季節に応じて何をするかを判定するサンプルコードを紹介します。

enum class Season {
    SPRING, SUMMER, AUTUMN, WINTER
}

fun main() {
    val currentSeason = Season.SUMMER
    val activity = when (currentSeason) {
        Season.SPRING -> "花見"
        Season.SUMMER -> "海水浴"
        Season.AUTUMN -> "紅葉狩り"
        Season.WINTER -> "スキー"
    }
    println("現在の季節は$currentSeasonで、$activityがおすすめです。")
}

このコードではSeasonというenumを定義し、その値(SPRING, SUMMER, AUTUMN, WINTER)に応じて行うべき活動(activity)をwhen式で判定しています。

実行すると「現在の季節はSUMMERで、海水浴がおすすめです。」と出力されます。

○サンプルコード9:when式を関数の引数で使用する

関数の引数として直接when式を使用することもできます。

これにより、コードがすっきりとまとまり、可読性も高まります。

fun greet(person: String, hour: Int) {
    val greeting = when (hour) {
        in 4..11 -> "おはよう"
        in 12..17 -> "こんにちは"
        else -> "こんばんは"
    }
    println("$personさん、$greeting!")
}

fun main() {
    greet("山田", 16)
    greet("佐藤", 23)
}

このコードでは、greet関数内で時間(hour)に応じて挨拶(greeting)を判定しています。

when式が直接関数内で使われており、この結果に基づいて出力が行われます。

この例を実行すると、”山田さん、こんにちは!” と “佐藤さん、こんばんは!” が出力されます。

○サンプルコード10:when式で独自クラスを扱う

Kotlinでは、独自クラスにもwhen式を応用することができます。

こうすることで、クラスのインスタンスに対して独自の処理を行う際に、コードの可読性と維持性が向上します。

具体的な例として、Carクラスとそのサブクラス(SportsCarTruckElectricCar)があり、それぞれの車種に応じた燃費計算を行いたいと思います。

// 車のクラス
open class Car

// スポーツカー
class SportsCar : Car()

// トラック
class Truck : Car()

// 電気車
class ElectricCar : Car()

// 燃費計算関数
fun calculateFuelEfficiency(car: Car): String {
    return when (car) {
        is SportsCar -> "燃費は少し悪いです。"
        is Truck -> "燃費は非常に悪いです。"
        is ElectricCar -> "燃費は非常に良いです。"
        else -> "詳細は不明です。"
    }
}

fun main() {
    val myCar: Car = SportsCar()
    val fuelEfficiency = calculateFuelEfficiency(myCar)
    println("この車の燃費状況:$fuelEfficiency")
}

このコードでは、まずCarクラスとそのサブクラス(SportsCarTruckElectricCar)を定義しています。

次にcalculateFuelEfficiency関数で、引数として受け取ったCarクラスのインスタンスがどのサブクラスに属するのかをwhen式で判定し、それぞれの車種に応じた燃費の状態を文字列で返しています。

この例を実行すると、"この車の燃費状況:燃費は少し悪いです。"と表示されます。

このようにして、when式を使うことで、独自クラスの種類に応じた処理をスッキリとかけます。

○サンプルコード11:複数の値を一つのブロックで処理する

when式では、複数の値に対して同じ処理を行いたい場合、それらを一つのブロックでまとめて処理することができます。

例として、月の名前を英語で受け取り、その月が何季に属するのかを判断するプログラムを作成します。

// 季節を判定する関数
fun determineSeason(month: String): String {
    return when (month) {
        "December", "January", "February" -> "冬"
        "March", "April", "May" -> "春"
        "June", "July", "August" -> "夏"
        "September", "October", "November" -> "秋"
        else -> "無効な月です"
    }
}

fun main() {
    val month = "October"
    val season = determineSeason(month)
    println("$monthは$seasonです。")
}

このコードはdetermineSeason関数内で、引数monthに応じて季節を判断しています。

特定の季節に該当する複数の月を一つのwhenブロックでまとめて処理しています。

このプログラムを実行すると、”Octoberは秋です。”と出力されます。

このように、when式を活用することで、条件が似たり寄ったりの場合にコードが冗長になるのを避け、簡潔に記述することが可能です。

○サンプルコード12:when式でコレクションを操作する

Kotlinのwhen式はコレクションとも連携できます。

コレクション内の要素が特定の条件に一致するかどうかをwhen式で判定することができます。

この手法は、一覧データやリストデータに対して条件別の処理を施す場合に特に役立ちます。

// コレクション内に特定の数値が存在するか確認する関数
fun containsNumber(numbers: List<Int>, target: Int): String {
    return when (target) {
        in numbers -> "リスト内に$targetが存在します。"
        !in numbers -> "リスト内に$targetは存在しません。"
        else -> "エラーが発生しました。"
    }
}

fun main() {
    val numbersList = listOf(1, 2, 3, 4, 5)
    val result = containsNumber(numbersList, 3)
    println(result)
}

このコードでは、containsNumber関数が特定の数値targetがリストnumbersに存在するかどうかを判定しています。

inキーワードを使用することで、特定の値がコレクション内に存在するかどうかを簡単にチェックできます。

その結果を文字列として返しています。

このコードを実行すると、コンソールには”リスト内に3が存在します。”と出力されます。

このように、when式を使ってコレクション内のデータに対する条件判断を行い、必要な処理を綺麗に記述できます。

○サンプルコード13:when式で高階関数を扱う

when式は高階関数と組み合わせて使用することも可能です。

高階関数は関数を引数に取ったり、関数を戻り値として返す関数のことを指します。

// 高階関数とwhen式を組み合わせる
fun operateOnNumbers(a: Int, b: Int, operator: (Int, Int) -> Int): Int {
    return when (operator) {
        ::add -> operator(a, b)
        ::subtract -> operator(a, b)
        else -> 0
    }
}

// 加算関数
fun add(a: Int, b: Int): Int {
    return a + b
}

// 減算関数
fun subtract(a: Int, b: Int): Int {
    return a - b
}

fun main() {
    val sum = operateOnNumbers(3, 4, ::add)
    val difference = operateOnNumbers(5, 2, ::subtract)
    println("合計:$sum")
    println("差:$difference")
}

このコードでは、operateOnNumbers関数が高階関数です。

この関数は2つの整数と、それらに対する操作を行う関数(加算または減算)を引数として受け取ります。

when式でoperatorの種類に応じた処理を選択しています。

このプログラムを実行すると、コンソールには”合計:7″と”差:3″が出力されます。

高階関数を用いることで、機能ごとにコードを分離でき、それをwhen式で効率よく呼び出すことができます。

○サンプルコード14:when式でセールス分析

when式はビジネスの現場でも非常に便利な機能であり、たとえばセールスデータの分析にも応用することができます。

ここでは、セールスのステータスに応じてさまざまな分析を行うプログラムのサンプルを紹介します。

// セールスデータを表すクラス
data class SalesData(val month: String, val revenue: Int)

// セールスデータに基づいて分析を行う関数
fun analyzeSales(salesData: SalesData) {
    when (salesData.revenue) {
        in 0..1000 -> println("${salesData.month}は低収益です。")
        in 1001..5000 -> println("${salesData.month}は中収益です。")
        in 5001..10000 -> println("${salesData.month}は高収益です。")
        else -> println("${salesData.month}は収益データが不明です。")
    }
}

fun main() {
    val january = SalesData("1月", 2000)
    val february = SalesData("2月", 7000)
    val march = SalesData("3月", 100)

    analyzeSales(january)
    analyzeSales(february)
    analyzeSales(march)
}

このサンプルコードでは、SalesDataというデータクラスを定義して月ごとのセールスデータ(月と収益)を管理しています。

analyzeSales関数では、このSalesDataクラスのインスタンスを引数に取り、revenueプロパティ(収益)に基づいて分析を行っています。

収益が0~1000、1001~5000、5001~10000のいずれに該当するかで、それぞれ低収益、中収益、高収益と分類しています。

このプログラムを実行すると、各月に対するセールス状況が次のように出力されます。

"1月は中収益です。"
"2月は高収益です。"
"3月は低収益です。"

○サンプルコード15:when式で独自の例外を投げる

エラーハンドリングにおいてもwhen式は活用できます。

特定の条件下で独自の例外を投げるケースを考えてみましょう。

class InvalidNumberException(message: String) : Exception(message)

fun checkNumber(num: Int) {
    when (num) {
        0 -> throw InvalidNumberException("ゼロは無効な値です。")
        in 1..10 -> println("正常な値です。")
        else -> println("範囲外の値です。")
    }
}

fun main() {
    try {
        checkNumber(0)
    } catch (e: InvalidNumberException) {
        println(e.message)
    }
}

このプログラムでは、独自の例外InvalidNumberExceptionを定義しています。

checkNumber関数内でwhen式を使って数値を評価し、0の場合にこの独自例外を投げています。

main関数でtry-catch構文を用いて例外を捕捉しています。

このコードを実行すると、”ゼロは無効な値です。”という例外メッセージが表示されることになります。

●詳細な対処法と注意点

Kotlinのwhen式を使用する際にはいくつかの制約や注意点が存在します。

これらを把握することで、より効率的で安全なコードを書くことが可能です。

○when式の制約

when式の便利さを最大限に活用するためには、その制約を理解することが重要です。

一つ目の制約として、when式は「全てのケースを網羅する必要がある」という点があります。

fun describeAnimal(animal: String) {
    when(animal) {
        "Dog" -> println("犬です")
        "Cat" -> println("猫です")
        else -> println("不明な動物です")
    }
}

このサンプルコードでは、動物の名前を受け取り、それが「Dog」か「Cat」かそれ以外かを判定しています。

この例でのポイントは、elseブロックを用意している点です。これにより、when式は全てのケースを網羅しています。

○パフォーマンスに関する注意

when式は非常に便利な機能ですが、大量のケースや複雑な条件を持つ場合には、パフォーマンスに影響を与える可能性があります。

fun complexWhen(x: Int) {
    when(x) {
        isEven(x) -> println("偶数です")
        isOdd(x) -> println("奇数です")
        else -> println("不明です")
    }
}

fun isEven(x: Int) = x % 2 == 0
fun isOdd(x: Int) = x % 2 != 0

このサンプルコードでは、偶数か奇数かを判定する条件が関数によって判定されています。

このような場合には、関数の処理が重いとwhen式全体のパフォーマンスが低下する可能性があります。

○読みやすいコードを書くためのヒント

最後に、when式を使う際にコードを読みやすく保つためのヒントです。

具体的には、各ケースのアクション(ブロック内の処理)が長くなりすぎると、コードが読みにくくなることがあります。

when(x) {
    1 -> {
        // 長い処理
        // ...
    }
    2 -> {
        // 長い処理
        // ...
    }
    else -> {
        // 長い処理
        // ...
    }
}

このような場合、各ケースの処理を外部の関数に切り出すことで、コードの可読性が高まります。

●カスタマイズ方法

Kotlinのwhen式は基本的な使い方から応用例まで非常に多様な使い方がありますが、更にその使い勝手を高めるためのカスタマイズ方法も存在します。

ここでは、独自の拡張やライブラリを使った応用例について説明します。

○when式の拡張

when式自体はKotlinの標準機能として提供されていますが、特定の目的に特化した処理を行いたい場合は、拡張関数を作成することで更に便利に使うことができます。

// 整数が素数であるかを判定する拡張関数
fun Int.isPrime(): Boolean {
    if (this <= 1) return false
    for (i in 2..Math.sqrt(this.toDouble()).toInt()) {
        if (this % i == 0) return false
    }
    return true
}

// when式で使用
fun describeNumber(num: Int) {
    when {
        num.isPrime() -> println("素数です")
        num % 2 == 0 -> println("偶数です")
        else -> println("その他の数値です")
    }
}

このコードでは、IntクラスにisPrime()という名前の拡張関数を定義しています。

その後、when式でこの拡張関数を使用して数値が素数であるかを判定しています。

describeNumber関数を呼び出すと、引数として渡された数値が素数か偶数か、それ以外かを判定して結果を出力します。

○ライブラリを使った応用例

外部ライブラリを使ってwhen式を更に強力にする方法もあります。

例えば、ArrowというKotlin向けの関数型プログラミングライブラリには、パターンマッチングを更に強化する機能が含まれています。

// Arrowライブラリを使った例
// (依存関係をプロジェクトに追加する必要があります)
import arrow.core.Some
import arrow.core.Option
import arrow.core.None

fun describeOption(option: Option<Int>): String =
    when(option) {
        is Some -> "値は${option.t}です"
        is None -> "値が存在しません"
    }

このコードの場合、ArrowライブラリのOptionクラスを用いています。

このOptionクラスは値が存在するかしないかの2つの状態を持つことができ、それをwhen式で簡単に処理することができます。

describeOption関数では、引数として渡されたOptionオブジェクトがSome(値が存在する)かNone(値が存在しない)かを判定し、適切なメッセージを返しています。

まとめ

Kotlinのwhen式は、コードの可読性と効率性を大幅に向上させる非常に有用な機能です。

この記事では、when式の基本的な使い方から応用例、さらにはカスタマイズ方法に至るまで、総計15の方法を詳細に説明してきました。

この記事がKotlinでwhen式を使いこなすための一助となれば幸いです。

初心者から中級者まで、多くのKotlin開発者がwhen式の有用性を高く評価しています。

ぜひこの機会に、when式を活用してコーディングの効率と品質を向上させてみてください。