もう迷わない!Kotlinの三項演算子とif式の使い分け完全ガイド
プログラミングにおける条件分岐は、コードに知性を与え、動的な振る舞いを実現するための根幹をなす要素です。多くのプログラミング言語では、この条件分岐を簡潔に記述するために「三項演算子」が提供されています。JavaやC++、JavaScriptなどを経験した方であれば、condition ? value_if_true : value_if_false
という形式でお馴染みでしょう。
しかし、あなたがKotlinの世界に足を踏み入れたとき、ある事実に気づいて驚くかもしれません。Kotlinには、この古典的な三項演算子が存在しないのです。
「え、じゃあ一行で条件分岐を書けないの?不便じゃない?」
そう思われたかもしれません。ご安心ください。Kotlinが三項演算子を採用しなかったのには明確な理由があり、そして、それを補って余りある、より強力で、より安全で、より読みやすい代替手段が用意されています。その中心的な役割を果たすのが、私たちがすでによく知っているif
です。ただし、Kotlinのif
は、あなたが思っているif
とは少し違う、「式」としての顔を持っています。
この記事は、Kotlinにおける条件分岐の記述方法、特に「三項演算子の代替としてのif
式」と、関連する強力なツールである「エルビス演算子(?:
)」、そして「when
式」の使い分けを、徹底的に、そして網羅的に解説する完全ガイドです。
この記事を読み終える頃には、あなたは以下のことを完全に理解しているでしょう。
- なぜKotlinに三項演算子がないのか、その設計思想の神髄
- Kotlinの
if
が「文」ではなく「式」であることの本当の意味と、そのパワー if
式、エルビス演算子、when
式を、どのような場面で、どのように使い分けるべきか- あなたの書くKotlinコードを、より簡潔で、安全で、そして何よりも「美しい」ものにするための具体的なテクニック
Javaから来た初心者の方も、すでにある程度Kotlinを書いているけれどコードをさらに洗練させたい中級者の方も、この記事があなたの迷いを断ち切り、自信を持って条件分岐を使いこなすための確かな道しるべとなることをお約束します。さあ、Kotlinの表現力豊かな世界の探求を始めましょう。
第1章: なぜKotlinには三項演算子がないのか? その深遠なる理由
物事を深く理解するためには、「何ができるか」だけでなく「なぜそうなっているのか」を知ることが不可欠です。Kotlinが三項演算子を導入しなかった理由を掘り下げることは、Kotlinという言語の根底に流れる設計哲学を理解する上で、非常に重要なステップとなります。
1.1. 振り返り: Javaにおける三項演算子の功罪
まず、比較対象としてJavaの三項演算子を見てみましょう。その主な役割は、if-else
文を一行で簡潔に記述することでした。
“`java
// Javaのコード
int a = 10;
int b = 20;
int max;
// if-else文を使う場合
if (a > b) {
max = a;
} else {
max = b;
}
// 三項演算子を使う場合
int max = (a > b) ? a : b;
“`
三項演算子を使ったコードは明らかに短く、単純なケースでは可読性も高いと言えます。これは三項演算子の紛れもない「功」の部分です。
しかし、その簡潔さは時として「罪」にもなり得ます。特に、三項演算子がネスト(入れ子)になった場合、その可読性は著しく低下します。
java
// Javaのコード: 読みにくいネストした三項演算子
int score = 85;
String result = (score >= 90) ? "Excellent" : ((score >= 70) ? "Good" : "Average");
このコードが何をしているか、一瞬で理解できるでしょうか?括弧の位置を注意深く追いながら、頭の中で分岐をシミュレートする必要があります。このようなコードは、バグの温床となりやすく、メンテナンス性も低いと言わざるを得ません。
1.2. Kotlinの設計哲学: 可読性と「式」の力
Kotlinの設計者たちは、このような三項演算子の功罪を深く理解した上で、より優れた解決策を言語に組み込みました。その核となるのが、以下の2つの設計哲学です。
1. 可読性 (Readability) の徹底的な追求
Kotlinは、コードが「書かれる回数」よりも「読まれる回数」の方が圧倒的に多いという事実を非常に重視しています。チーム開発や将来の自分によるメンテナンスを考えたとき、コードの読みやすさは生産性に直結します。
ネストした三項演算子のような、一見巧妙に見えても可読性を損なう可能性のある機能は、Kotlinの哲学とは相容れません。Kotlinは、常に明確で、意図が伝わりやすいコードを書くことをプログラマーに推奨します。
2. ほとんどの制御構造は「式 (Expression)」である
ここが最も重要なポイントです。Kotlinでは、if
やwhen
、try-catch
といった多くの制御構造が、値を返さない「文(Statement)」ではなく、評価結果として値を返す「式(Expression)」として設計されています。
- 文 (Statement): アクションを実行するが、それ自体は値を持たない。Javaの
if-else
文やfor
ループがこれにあたります。 - 式 (Expression): 評価されると必ず何らかの値を生成する。
1 + 2
や"Hello".length()
などが典型的な例です。
Javaでは、if
は文でした。そのため、条件分岐の結果を変数に代入するには、三項演算子という特別な構文が必要だったのです。
しかし、Kotlinではif
自体が式です。つまり、if
ブロックが評価された結果、値を直接返すことができるのです。
kotlin
// Kotlinのif式
val a = 10
val b = 20
val max = if (a > b) a else b // ifが値を返し、直接maxに代入される
このコードを見てください。これはJavaの三項演算子と全く同じ役割を果たしていますが、使われているのは見慣れたif
とelse
のキーワードだけです。ネストした場合でも、その構造は通常のif-else if-else
と同様になり、三項演算子のような可読性の低下は起こりにくくなります。
結論として、Kotlinに三項演算子がないのは、それが不要だからです。 より可読性が高く、より一貫性があり、より強力なif
式がその役割を完全に代替しているため、わざわざ別の構文を導入する必要がなかったのです。これは、言語をシンプルに保ちつつ、表現力を高めるというKotlinの見事な設計思想の表れと言えるでしょう。
第2章: Kotlinのif式 – 基本から応用まで、三項演算子を超える力
前章で、Kotlinのif
が「式」であることが三項演算子を不要にする鍵だと学びました。この章では、そのif
式の能力を余すところなく引き出すための、基本的な使い方から応用的なテクニックまでを詳しく見ていきましょう。
2.1. ウォームアップ: 文としてのif
まずは、他の多くの言語と同じ「文」としてのif
の使い方を復習しておきましょう。これは特定の条件下で何らかのアクション(副作用、例えばコンソールへの出力など)を実行するだけで、値を返さない使い方です。
kotlin
fun printWeather(temperature: Int) {
if (temperature > 25) {
println("It's a hot day!")
} else if (temperature < 10) {
println("It's a cold day, bring a jacket.")
} else {
println("The weather is pleasant.")
}
}
この使い方は、JavaやC++などと何ら変わりません。if
ブロックの中の処理が実行されるだけで、if
全体として何かの値を生み出すわけではありません。
2.2. 本番: 式としてのif (三項演算子の完全代替)
ここからがKotlinの真骨頂です。if
を「式」として使い、その結果を変数に代入したり、関数の戻り値として直接使ったりする方法を見ていきます。
基本形
Javaのint max = (a > b) ? a : b;
を、Kotlinのif
式で書くとこうなります。
“`kotlin
val a = 10
val b = 20
// if式を使い、結果をmax変数に代入する
val max = if (a > b) a else b
println(max) // 出力: 20
“`
なんとシンプルで直感的でしょうか。?
や:
といった記号を覚える必要はなく、if (条件) 真の場合の値 else 偽の場合の値
という自然な英語に近い形で記述できます。
ブロック {}
の使い方
if
やelse
の分岐先が単純な値でなく、少し複雑な処理を含む場合でも問題ありません。ブロック{}
を使うことができます。ブロックが使われた場合、そのブロックの最後の式が、その分岐の値として返されます。
“`kotlin
val a = 10
val b = 20
val max = if (a > b) {
println(“a is greater”) // この行は実行されるが、値にはならない
a // このブロックの最後の式である ‘a’ が値として返る
} else {
println(“b is greater or equal”) // この行も実行されるだけ
b // このブロックの最後の式である ‘b’ が値として返る
}
println(max) // 出力: 20
“`
この特性は非常に強力です。値の計算途中でログを出力したり、何らかの準備処理をしたりといったことが、式の中で完結します。これにより、結果を保持するためだけの一時変数を宣言する必要がなくなり、コードがクリーンになります。
else
の必須性: 安全性への貢献
if
を「文」として使う場合、else
は任意でした。if (condition) { ... }
のように、else
がないif
文は頻繁に書かれます。
しかし、if
を「式」として使う場合、else
は必ず記述しなければなりません。
kotlin
// コンパイルエラー!
// 'if' must have both main and 'else' branches if used as an expression.
val result = if (a > b) a
なぜでしょうか?答えは単純です。「式」は必ず何らかの値を返さなければならないからです。もしelse
がなければ、a > b
がfalse
だった場合にresult
変数に代入すべき値が存在しなくなってしまいます。
Kotlinコンパイラは、このような曖昧さを許しません。else
を強制することで、式が必ず値を返すことを保証し、実行時エラーにつながる潜在的なバグをコンパイル時に防いでくれるのです。これはKotlinの安全性(Safety)という思想を体現しています。
2.3. 応用: 複数行にわたる複雑なロジック
if
式の真価は、三項演算子では到底表現できないような、複数行にわたるロジックを扱える点にあります。
例えば、ユーザーのステータスに応じて、異なる方法でウェルカムメッセージを生成するシナリオを考えてみましょう。
“`kotlin
// 悪い例: if式の外で一時変数を使う
val user = User(name = “Alice”, isPremium = true, loginCount = 10)
var message: String // 可変(var)の一時変数が必要になる
if (user.isPremium) {
// プレミアムユーザー向けの複雑なメッセージ生成ロジック
val bonusPoints = user.loginCount * 10
message = “Welcome back, premium member ${user.name}! You’ve earned $bonusPoints bonus points.”
} else {
// 通常ユーザー向けのメッセージ
message = “Hello, ${user.name}. Welcome to our service!”
}
println(message)
“`
このコードは動作しますが、message
を可変のvar
として宣言する必要があります。Kotlinでは、可能な限り不変のval
を使うことが推奨されており(イミュータビリティ)、このコードは少し冗長に見えます。
これをif
式を使ってリファクタリングしてみましょう。
“`kotlin
// 良い例: if式を使って不変のvalに直接代入
val user = User(name = “Alice”, isPremium = true, loginCount = 10)
val message = if (user.isPremium) {
// ブロック内で計算を行い…
println(“Calculating premium user message…”)
val bonusPoints = user.loginCount * 10
// 最後の式が文字列として返る
“Welcome back, premium member ${user.name}! You’ve earned $bonusPoints bonus points.”
} else {
“Hello, ${user.name}. Welcome to our service!”
}
println(message)
“`
どうでしょうか。message
は不変のval
として一度に初期化され、if-else
の各ブロックがそれぞれのメッセージ生成ロジックに責任を持つ、非常にクリーンで読みやすいコードになりました。一時変数が不要になり、変数のスコープも最小限に抑えられています。
2.4. if-else if-else
チェーン
もちろん、if
式はelse if
と組み合わせることも可能です。これにより、三項演算子では非常に読みにくくなる多岐分岐も、自然な形で表現できます。
“`kotlin
val score = 75
val grade: Char = if (score >= 90) {
‘A’
} else if (score >= 80) {
‘B’
} else if (score >= 70) {
‘C’
} else if (score >= 60) {
‘D’
} else {
‘F’
}
println(“Your grade is $grade”) // 出力: Your grade is C
“`
このように、if
式は単純な二者択一から複雑な多岐分岐まで、一貫した構文で柔軟に対応できる、非常に強力なツールなのです。ただし、このようなif-else if
チェーンが長くなる場合は、後述するwhen
式の方がさらに適している場合があります。
第3章: もう一つの強力な代替手段: エルビス演算子 ?:
Kotlinが提供する三項演算子の代替はif
式だけではありません。特定のシナリオ、すなわち「nullチェックとデフォルト値の設定」において絶大な威力を発揮するのが、ユニークな名前を持つエルビス演算子(?:
)です。
3.1. Nullチェックという古くからの課題
プログラミング、特にJavaのような言語において、NullPointerException
は最も頻繁に遭遇する悪夢の一つでした。これを避けるため、私たちは頻繁にnullチェックを行います。三項演算子は、このnullチェックとデフォルト値の設定にもよく使われてきました。
java
// Javaのコード
// userがnull、またはuser.getName()がnullの可能性がある
String name = (user != null && user.getName() != null) ? user.getName() : "Guest";
このコードは、変数がnullでないことを確認し、nullでなければその値を、nullであれば代替のデフォルト値を設定するという、非常によくあるパターンです。
3.2. Kotlinの救世主: エルビス演算子 ?:
登場
Kotlinは、このような頻出パターンを、よりエレガントかつ安全に記述するための専用の構文を用意しました。それがエルビス演算子です。
エルビス演算子(?:
)は、その形がエルビス・プレスリーの横顔と髪型に似ていることから名付けられました。その動作は非常にシンプルです。
left ?: right
この式は、まず左辺(left
)を評価します。
* もしleft
がnullでなければ、left
の値が式全体の結果となります。
* もしleft
がnullであれば、右辺(right
)が評価され、その値が式全体の結果となります。
このエルビス演算子と、null許容型(?
)のプロパティに安全にアクセスするためのセーフコール演算子(?.
)を組み合わせることで、先のJavaのコードは劇的に簡潔になります。
“`kotlin
// userはUser?型(nullの可能性がある)
// user.nameもString?型(nullの可能性がある)
// セーフコールとエルビス演算子の組み合わせ
val name = user?.name ?: “Guest”
“`
この一行が何をしているか分解してみましょう。
user?.name
:user
がnull
でなければ、user.name
にアクセスします。user
がnull
であれば、この式全体がnull
になります。NullPointerException
は発生しません。
... ?: "Guest"
:user?.name
の結果がnull
でなければ(つまり、user
もuser.name
もnull
でなかった場合)、その名前がname
に代入されます。user?.name
の結果がnull
であれば(user
がnull
か、user.name
がnull
だった場合)、「Guest
」という文字列がname
に代入されます。
たった一行で、Javaでは冗長になりがちだったnullチェックとデフォルト値の設定が、非常に安全かつ宣言的に記述できています。
3.3. エルビス演算子のさらなる力: 早期リターン
エルビス演算子の右辺に置けるのは、単なる値だけではありません。return
やthrow
といった、コードの実行フローを中断させる式を置くこともできます。これがエルビス演算子を単なるデフォルト値設定ツール以上の存在にしています。
return
との組み合わせ
関数内で、ある値がnull
であってはならない場合に、null
だったら即座に関数を終了させる、というガード節(Guard Clause)のパターンです。
“`kotlin
fun printShippingLabel(customer: Customer?) {
// customerまたはそのaddressがnullなら、何もせずに関数を抜ける
val address = customer?.address ?: return
// この行に到達した時点で、addressはnullでないことが保証されている(String型)
println("Shipping to: $address")
}
``
if (customer == null || customer.address == null) { return }` と書くよりも遥かに簡潔です。
このコードは、
throw
との組み合わせ
値がnull
であることが許されない、契約違反であるような場合には、例外をスローすることもできます。
“`kotlin
fun getRequiredConfigValue(key: String): String {
val value = configMap[key] // configMapから値を取得。存在しなければnull
// valueがnullなら例外をスローする。
// nullでなければ、null非許容のString型として返される。
return value ?: throw IllegalArgumentException("Required config key '$key' not found.")
}
``
String`(null非許容)を返すと宣言しており、エルビス演算子がその契約をランタイムで保証してくれます。
このパターンも非常に強力です。関数のシグネチャは
3.4. 使い分け: if式 vs エルビス演算子
では、if
式とエルビス演算子はどのように使い分ければよいのでしょうか。ガイドラインは明確です。
-
エルビス演算子 (
?:
) を使うべきとき:- 目的が「nullかどうか」のチェックであり、nullの場合にデフォルト値を設定したり、フローを中断(
return
,throw
)したりする場合。 - このシナリオでは、エルビス演算子が最も意図を明確に、そして簡潔に表現できます。
- 目的が「nullかどうか」のチェックであり、nullの場合にデフォルト値を設定したり、フローを中断(
-
if
式を使うべきとき:- 条件がnullチェック以外の場合。 例えば、数値の大小比較、真偽値のチェック、文字列の内容比較など、一般的な条件分岐全般。
val result = if (count > 0) "Has items" else "Empty"
のようなケースです。
両者は競合する関係ではなく、それぞれの得意分野を持つ補完的な関係です。「nullなら〜」と考えたらエルビス演算子を、「もし〜なら〜」と考えたらif
式を、という思考の癖をつけると良いでしょう。
第4章: if
式を超える選択肢: when
式
if
式は三項演算子の優れた代替品ですが、分岐が多くなるとif-else if-else if-...
というチェーンが長くなり、少し見通しが悪くなることがあります。そんなとき、Kotlinにはさらに強力で表現力豊かな選択肢が用意されています。それがwhen
式です。
when
式は、他の言語におけるswitch-case
文に似ていますが、その能力はswitch
を遥かに凌駕します。
4.1. if-else if
チェーンからの卒業
第2章で見た成績評価のコードを思い出してみましょう。
kotlin
// if-else if チェーン
val grade = if (score >= 90) 'A'
else if (score >= 80) 'B'
else if (score >= 70) 'C'
else if (score >= 60) 'D'
else 'F'
このコードをwhen
式で書き換えると、以下のようになります。
kotlin
// when式を使った場合
val grade = when {
score >= 90 -> 'A'
score >= 80 -> 'B'
score >= 70 -> 'C'
score >= 60 -> 'D'
else -> 'F'
}
if
とelse if
の繰り返しが消え、条件と結果の対(->
で区切られる)がリストのように並び、構造がより明確になりました。このように、引数を取らないwhen
は、if-else if
チェーンの完全な上位互換として機能します。
4.2. when
式のスーパーパワー
when
の真価は、その柔軟な条件式にあります。
特定の値との比較
switch
文のように、特定の値と一致するかどうかをチェックできます。
“`kotlin
val httpStatusCode = 200
val message = when (httpStatusCode) {
200 -> “OK”
403 -> “Forbidden”
404 -> “Not Found”
else -> “Unknown status”
}
“`
複数の値をまとめる
カンマ(,
)で区切ることで、複数の値を同じ分岐にまとめることができます。
kotlin
when (httpStatusCode) {
200, 201, 204 -> "Success"
400, 401, 403, 404 -> "Client Error"
500, 503 -> "Server Error"
else -> "Other"
}
範囲(Range)やコレクションとの照合
in
キーワードを使うことで、値が特定の範囲やコレクションに含まれるかをチェックできます。
“`kotlin
val temperature = 15
val description = when (temperature) {
in -50..0 -> “Freezing”
in 1..10 -> “Cold”
in 11..20 -> “Cool”
in 21..30 -> “Warm”
!in -50..50 -> “Extreme temperature” // !in
で範囲外もチェック可能
else -> “Hot”
}
“`
型のチェック
is
キーワードを使えば、変数の型をチェックし、その分岐内では自動的にその型にスマートキャスト(型推論)してくれます。
kotlin
fun processValue(value: Any) {
when (value) {
is String -> println("It's a String with length ${value.length}") // valueはStringとして扱える
is Int -> println("It's an Int, its double is ${value * 2}") // valueはIntとして扱える
is List<*> -> println("It's a List with size ${value.size}") // valueはListとして扱える
else -> println("Unknown type")
}
}
else
の強制による網羅性の保証
if
式と同様に、when
を「式」として(つまり、結果を変数に代入したり関数の戻り値として使う)場合、コンパイラは分岐が網羅的であることを要求します。考えられる全てのケースがカバーされていない場合、else
分岐の追加を強制します。
これにより、「条件の考慮漏れ」というよくあるバグを防ぐことができます。特に、Enum
やSealed Class
と組み合わせた場合、全てのメンバーを網羅すればelse
が不要になるなど、コンパイラが強力に安全性をサポートしてくれます。
4.3. 使い分け: if
式 vs when
式
これで、条件分岐のための3つの主要なツール、if
式、エルビス演算子、when
式が出揃いました。if
とwhen
の使い分けは、コードの可読性を最大化するための重要な判断です。
-
if
式を使うべきとき:- 条件が単純な二者択一(true/false)の場合。 このシナリオでは
if
式が最もシンプルで、意図が直接的に伝わります。 val state = if (isLoggedIn) "Online" else "Offline"
のようなケース。これをwhen
で書くのは冗長です。
- 条件が単純な二者択一(true/false)の場合。 このシナリオでは
-
when
式を使うべきとき:- 分岐が3つ以上ある場合。
if-else if-else
チェーンを書きたくなったら、それはwhen
式を検討すべきサインです。 - 条件が単純な真偽値ではなく、値、範囲、型など、多様なものである場合。
when
の柔軟な条件式が活きる場面です。
- 分岐が3つ以上ある場合。
if
式が「ナイフ」なら、when
式は「スイスアーミーナイフ」に例えられます。パンを切るだけならナイフで十分ですが、缶切りやドライバーが必要ならスイスアーミーナイフが役立ちます。道具の特性を理解し、状況に応じて最適なものを選択することが、優れた職人(プログラマー)の条件です。
第5章: 実践的な使い分けとベストプラクティス
これまでの章で学んだ知識を統合し、実際のプログラミングで遭遇する様々なシナリオにおいて、どの構文を選択すべきか、そして、どのように書けば最もクリーンなコードになるのかを考えていきましょう。
シナリオ1: 変数への値の代入
-
ケースA: 単純な真偽値に基づく代入
- 最適解:
if
式
kotlin
val isLoggedIn = true
val statusText = if (isLoggedIn) "Logged In" else "Logged Out" - 理由: 最もシンプルで直接的。
when
を使うまでもない。
- 最適解:
-
ケースB: Nullチェックとデフォルト値
- 最適解: エルビス演算子
?:
kotlin
val userName: String? = fetchUserName() // nullを返すかもしれない
val displayName = userName ?: "Guest" - 理由: nullチェックの意図が最も明確。
if (userName != null) userName else "Guest"
よりも遥かに簡潔。
- 最適解: エルビス演算子
-
ケースC: 複数の条件に基づく多岐分岐
- 最適解:
when
式
“`kotlin
enum class OrderStatus { PENDING, PROCESSING, SHIPPED, DELIVERED, CANCELED }
val currentStatus = OrderStatus.PROCESSING
val userMessage = when (currentStatus) {
OrderStatus.PENDING -> “Your order is waiting for confirmation.”
OrderStatus.PROCESSING -> “We are preparing your order.”
OrderStatus.SHIPPED -> “Your order is on its way!”
OrderStatus.DELIVERED -> “Your order has been delivered.”
OrderStatus.CANCELED -> “Your order has been canceled.”
// Enumの全ケースを網羅しているのでelseは不要
}
``
if-else if`よりも構造が明確で、網羅性をコンパイラがチェックしてくれる。
* 理由: - 最適解:
シナリオ2: 関数の戻り値として使う
Kotlinでは、式を直接関数の戻り値とすることができます。return
キーワードと共に使うことも、=
を使った単一式関数(Single-Expression Function)として定義することも可能です。
-
if
式を使った単一式関数
kotlin
fun max(a: Int, b: Int): Int = if (a > b) a else b -
エルビス演算子を使った単一式関数
kotlin
fun getCartItemCount(user: User?): Int = user?.cart?.itemCount ?: 0 -
when
式を使った単一式関数
kotlin
fun getIconForFileType(fileType: String): Icon = when (fileType) {
"jpg", "png" -> Icon.IMAGE
"mp4", "avi" -> Icon.VIDEO
"pdf" -> Icon.DOCUMENT
else -> Icon.GENERIC
}
単一式関数はコードを非常にコンパクトにしますが、ロジックが複雑になる場合は、通常の関数本体{}
とreturn
文を使った方が可読性が高まることもあります。常に読みやすさを優先しましょう。
シナリオ3: 可読性を最大化するためのベストプラクティス
1. ネストを避ける
if
やwhen
の中に、さらにif
やwhen
をネストさせると、コードの複雑さが急激に増大します。ネストは可能な限り避けましょう。
-
悪い例 (深いネスト):
kotlin
val result = if (user != null) {
if (user.isActive) {
if (user.hasPermissions()) {
"Allowed"
} else {
"Permission Denied"
}
} else {
"User Inactive"
}
} else {
"User Not Found"
} -
良い例 (早期リターン/ガード節でフラットに):
“`kotlin
fun checkAccess(user: User?): String {
if (user == null) return “User Not Found”
if (!user.isActive) return “User Inactive”
if (!user.hasPermissions()) return “Permission Denied”return "Allowed"
}
“` -
良い例 (
when
式でフラットに):
kotlin
val result = when {
user == null -> "User Not Found"
!user.isActive -> "User Inactive"
!user.hasPermissions() -> "Permission Denied"
else -> "Allowed"
}
2. 複雑なロジックは関数に切り出す
if
やwhen
の条件式、あるいはそのブロック内が長くなってきたら、それはロジックを別の関数に切り出す良い機会です。適切に命名された関数は、コードを自己文書化します。
-
リファクタリング前:
kotlin
val discount = if (user.isPremium && user.purchaseHistory.sum() > 1000 && !user.isFlagged) {
0.2
} else {
0.05
} -
リファクタリング後:
“`kotlin
fun isEligibleForVipDiscount(user: User): Boolean {
return user.isPremium
&& user.purchaseHistory.sum() > 1000
&& !user.isFlagged
}val discount = if (isEligibleForVipDiscount(user)) 0.2 else 0.05
“`
コードの意図が格段に分かりやすくなりました。
3. 冗長な表現を避ける
- アンチパターン:
if (condition) true else false
- これは
condition
そのものと全く同じです。
kotlin
// 悪い例
val isVisible = if (count > 0) true else false
// 良い例
val isVisible = count > 0
- これは
まとめフローチャート
あなたの思考を整理するために、簡単なフローチャートを提示します。
┌──────────────────────────┐
│ 条件分岐で値を返したい! │
└──────────┬──────────┘
│
▼
┌──────────────────────────┐
│ 条件は「Nullかどうか」? │ Yes ──► エルビス演算子 `?:` を使う
└──────────┬──────────┘
│ No
▼
┌──────────────────────────┐
│ 条件は「単純な2択」? │ Yes ──► `if`式 を使う
└──────────┬──────────┘
│ No
▼
┌──────────────────────────┐
│ 分岐が3つ以上 or 複雑な条件?│ Yes ──► `when`式 を使う
└──────────────────────────┘
結論: もう迷わない、表現豊かな条件分岐の世界へ
私たちは長い旅を経て、Kotlinがなぜ三項演算子を持たないのか、そしてその代わりにどれほど強力で洗練されたツールを提供しているのかを学びました。
もはや、Kotlinに三項演算子がないことを嘆く必要はありません。むしろ、その不在がもたらす一貫性と可読性の高さを歓迎すべきです。
最後に、今日学んだことを簡潔にまとめましょう。
if
式: Kotlinの「基本の三項演算子」。単純な二者択一のシナリオで最も輝きます。三項演算子にできてif
式にできないことはなく、複数行のロジックを記述できる点で遥かに強力です。- エルビス演算子 (
?:
): Nullチェックとデフォルト値設定のスペシャリスト。セーフコール(?.
)と組み合わせることで、null安全なコードを驚くほど簡潔に記述できます。早期リターン(return
,throw
)にも使え、非常に用途が広いです。 when
式:if-else if
チェーンの王様。3つ以上の分岐や、値・範囲・型などに基づく複雑な条件分岐で圧倒的な可読性と表現力を発揮します。コンパイラによる網羅性のチェックは、コードの堅牢性を飛躍的に高めます。
これらの3つのツールは、互いに競合するものではなく、それぞれの得意分野を持つ見事なトリオです。シナリオに応じて適切なツールを選択するスキルは、あなたのKotlinコードを一段上のレベルへと引き上げるでしょう。
さあ、今日から自信を持って、あなたのプロジェクトでこれらの式を使いこなしてください。よりクリーンで、より安全で、そして何よりも読んでいて楽しい、表現力豊かなコードを書く。それこそがKotlinプログラミングの醍醐味なのですから。