はじめに
自己紹介
皆さん、こんにちは、Udemy講師の斉藤賢哉です。私はこれまで、25年以上に渡って企業システムの開発に携わってきました。特にアーキテクトとして、ミッションクリティカルなシステムの技術設計や、Javaフレームワーク開発などの豊富な経験を有しています。
様々なセミナーでの登壇や雑誌への技術記事寄稿の実績があり、また以下のような書籍も執筆しています。
いずれもJava EE(Jakarta EE)を中心にした企業システム開発のための書籍です。中でも 「アプリケーションアーキテクチャ設計パターン」は、(Javaに限定されない)比較的普遍的なテーマを扱っており、内容的にはまだまだ陳腐化していないため、興味のある方は是非手に取っていただけると幸いです(中級者向け)。
Udemy講座のご紹介
この記事の内容は、私が講師を務めるUdemy講座『Java Basic編』の一部の範囲をカバーしたものです。『Java Basic編』はこちらのリンクから購入できます(セールス対象外のためいつも同じ価格)。また定価の約30%OFFで購入可能なクーポンをQiita内で定期的に発行していますので、興味のある方は、ぜひ私の他の記事をチェックしてみてください。
この講座は、以下のような皆様にお薦めします。
- Javaの言語仕様や文法を正しく理解すると同時に、現場での実践的なスキル習得を目指している方
- 新卒でIT企業に入社、またはIT部門に配属になった、新米システムエンジニアの方
- 長年IT部門で活躍されてきた中堅層の方で、学び直し(リスキル)に挑戦しようとしている方
- 今後、フリーランスエンジニアとしてのキャリアを検討している方
- 「Chat GPT」のエンジニアリングへの活用に興味のある方
- 「Oracle認定Javaプログラマ」の資格取得を目指している方
- IT企業やIT部門の教育研修部門において、新人研修やリスキルのためのオンライン教材をお探しの方
この記事を含むシリーズ全体像
この記事はJava SEの一部の機能・仕様を取り上げたものですが、一連のシリーズになっており、シリーズ全体でJava SEを網羅しています。また認定資格である「Oracle認定Javaプログラマ」(Silver、Gold)の範囲もカバーしています。シリーズの全体像および「Oracle認定Javaプログラマ」の範囲との対応関係については、以下を参照ください。
6.2 条件分岐
チャプターの概要
制御構文には、大きく分けて条件分岐と繰り返しがありますが、このチャプターでは、まず条件分岐の実装方法について学びます。
条件分岐は、Javaによるアプリケーションを構築するうえで非常に重要な処理です。
6.2.1 if文~単純分岐と多岐分岐
条件分岐のパターン
条件分岐とは、何らかの条件が真すなわちtrueなのか偽すなわちfalseなのかによって、処理を分岐させることです。条件分岐には、処理を二系統に分岐させる「単純分岐」と、多系統に分岐させる「多岐分岐」があります。また、分岐には階層という概念があります。分岐の階層が一階層のみのケースもあれば、階層がネストするケースもあります。
このような条件分岐の様々なパターンを考える上で、ここでは身近にあるECサイトのアプリケーションを題材にします。
単純分岐(1)~if文
まずは単純分岐のうち、条件がtrueの場合のみ処理を追加するケースです。
フローチャートは以下のようになります。
このような処理を実現するためには、if文を使用します。
if文の構文は以下のとおりです。
if (条件式) {
....条件式がtrueの場合の処理....
}
if文では、ifキーワードに後ろに( )
で囲って条件式を指定します。ifキーワードと( )
の間のスペースは任意ですが、可読性確保のためにスペースを1つ入れるのが一般的です。
条件式には、boolean型変数か、評価結果がboolean型となる式を指定します。そして条件式がtrueだった場合の処理を、後ろのブロックに記述します。このケースをECサイトの例で考えると、顧客がゴールド会員の場合に限り100ポイントが加算される、といった処理が相当します。
この処理をコードで表現すると、以下のようになります。
if (customerType == GOLD_CUSTOMER) {
point += 100; // 100ポイント加算される
}
このコードにおける"GOLD_CUSTOMER"は定数と呼ばれるものですが、ここでは「ゴールド会員を表す値」と理解しておけば問題ありません。
「顧客がゴールド会員かどうか」という判定結果が、isGoldCustomerというboolean型変数に格納されている場合は、以下のようになります。
boolean isGoldCustomer = true; // またはfalse
if (isGoldCustomer) {
point += 100; // 100ポイント加算される
}
またifブロック内の命令文が一行の場合は、{ }
を省略することも可能です。
if (条件式) ....条件式がtrueの場合の処理....
単純分岐(2)~if-else文
次に条件がtrue、falseのそれぞれで処理を切り替えるケースです。
フローチャートは以下のようになります。
今度は、条件式の評価結果がtrueだった場合の処理をifブロックに記述するだけではなく、条件式の評価結果がfalseだった場合の処理をelseブロックに記述します。
if-else文の構文は以下のとおりです。
if (条件式) {
....条件式がtrueの場合の処理(1)....
} else {
....条件式がfalseの場合の処理(2)....
}
このケースは、ECサイトの例で考えると、購入金額が10000円以上の場合は配送料は300円、10000円未満の場合は配送料は900円になる、といった処理が相当します。このような条件分岐において、処理の境界にあたる値(ここでは購入金額10000円)を「境界値」と呼びます。
さてこの処理をコードで表現すると、以下のようになります。
int deliveryFee; //【1】
if (10000 <= totalPrice) { //【2】
deliveryFee = 300; //【3】
} else {
deliveryFee = 900; //【4】
}
配送料を表す変数deliveryFeeは、ifブロック、elseブロック、それぞれの分岐の中で値の代入が必要のため、変数のスコープを考慮すると、if-else文の外側【1】で宣言する必要があります。if文に指定された条件式【2】により、購入金額(変数totalPrice)が10000円以上の場合はifブロックに入り、配送料(変数deliveryFee)は300円に決まります【3】。また購入金額が10000円未満の場合はelseブロックに入り、配送料は900円になります【4】。
多岐分岐~if-else-if文
次にif-else-if文による多岐分岐です。if-else-if文による多岐分岐では、複数の条件式によって処理を多系統に分岐させます。ここでは3系統に分岐させるものとします。
フローチャートは以下のようになります。
if-else-if文の構文は以下のとおりです。
if (条件式A) {
....条件式Aがtrueの場合の処理(1)....
} else if (条件式B) {
....条件式Bがtrueの場合の処理(2)....
} else {
....条件式AとBがともにfalseの場合の処理(3)....
}
まずifキーワードに条件式を指定し、最初の分岐処理を記述します。次に、最初の分岐がfalseだった場合のフローとしてelse ifキーワードに条件式を指定し、第二の分岐処理を記述します。最後に、2つの分岐がいずれもfalseだった場合のフローとして、elseキーワードの後ろに第三の分岐処理を記述します。
このパターンはECサイトの例で考えると、購入金額が10000円以上の場合は配送料は300円、5000円以上の場合は配送料は600円、5000円未満の場合は配送料は900円になる、といった処理が相当します。これをコードで表現すると、以下のようになります。
int deliveryFee;
if (10000 <= totalPrice) { //【1】
deliveryFee = 300;
} else if (5000 <= totalPrice) { //【2】
deliveryFee = 600;
} else {
deliveryFee = 900;
}
このコードでは、例えば購入金額(変数totalPrice)が12000円の場合は【1】の分岐がtrueになるため配送料(変数deliveryFee)は300円になります。このときこのifブロックの処理が終わるとif文全体から抜けるため、【2】の分岐には到達しません。購入金額が8000円の場合は【1】の分岐はfalseになり、【2】の分岐がtrueになるため配送料は600円になります。また購入金額が3000円の場合は【1】、【2】の分岐がともにfalseになるため、配送料は900円になります。
ここで気を付けなければならないのは、【1】と【2】の条件式の順番です。以下のコードを見てください。
int deliveryFee;
if (5000 <= totalPrice) { //【1】
deliveryFee = 600;
} else if (10000 <= totalPrice) { //【2】
deliveryFee = 300;
} else {
deliveryFee = 900;
}
【1】と【2】のブロックを入れ替えると、購入金額が10000円以上になった場合、【1】ブロックに入ってしまうため仕様通りに処理を実行できません。このようにif-else-if文による多岐分岐では、先に登場する条件式の範囲を常に狭くする必要がある点に注意してください。
6.2.2 if文~2つ以上の変数による分岐
2つ以上の変数による分岐
レッスン6.2.1は条件式の判定に用いる変数が1つしかないパターンでしたが、このレッスンでは2つ以上の変数を条件式判定に用いるパターンを見ていきます。ECサイトの例では「顧客種別と購入金額の組み合わせから配送料を決定する」といった条件分岐です。
このような条件分岐には、以下のような方法があります。
- 論理演算子を使用する方法
- 条件分岐をネストさせる方法
ここでは両者を比較するための題材として、以下のような仕様に基づいて配送料が決まる、という例を取り上げます。すなわち「ゴールド会員の場合に限り、購入金額が3000円以上になると特別優遇されて配送料は無料(それ以外は配送料は600円)」という仕様です。
これを2軸のマトリックスで表現すると、以下のようになります。
【表6-2-1】顧客種別・購入金額と配送料
ゴールド会員 | 一般会員 | |
---|---|---|
3000円以上 | 0円(特別優遇) | 600円 |
3000円未満 | 600円 | 600円 |
また顧客種別、購入金額という2つの説明変数と、配送料という目的変数の組み合わせを表で表すと、以下のようになります。このような表を「直交表」と呼びます。
【表6-2-2】顧客種別*購入金額*配送料の直交表1
項番 | 顧客種別 | 購入金額 | 配送料 |
---|---|---|---|
1 | ゴールド会員 | 3000円以上 | 0円(特別優遇) |
2 | ゴールド会員 | 3000円未満 | 600円 |
3 | 一般会員 | すべて | 600円 |
論理演算子を使用する方法
前項で示した仕様は、論理演算子によって条件分岐を記述することができます。論理積を表す演算子&&
を使用してコードを記述すると、以下のようになります。なおGOLD_CUSTOMERは、ゴールド会員を表す定数(チャプター8.2参照)です。
int deliveryFee;
if (customerType == GOLD_CUSTOMER && 3000 <= totalPrice) {
deliveryFee = 0;
} else {
deliveryFee = 600;
}
if文の条件式の中で、論理演算子&&
が使われている点に注目してください。このように記述すると、顧客種別(変数customerType)がゴールド会員であり、かつ、購入金額(変数totalPrice)が3000円以上の場合に、条件式全体がtrueになるため、ifブロックに入ります。またそれ以外の場合は、elseブロックに入ります。その結果、顧客種別がゴールド会員であり、かつ、購入金額が3000円以上の場合は配送料が0円、それ以外の場合は配送料は600円に決まります。
次にド・モルガンの法則を適用して論理積を論理和に変換すると、以下のように記述することも可能です。
int deliveryFee;
if (customerType != GOLD_CUSTOMER || ! (3000 <= totalPrice)) {
deliveryFee = 600;
} else {
deliveryFee = 0;
}
このif文では「顧客種別がゴールド会員ではないか、または購入金額が3000円以上でない場合は、配送料は通常料金の600円、それ以外の場合は特別優遇されて無料」にしています。これは既出の仕様と、論理的には同じことを意味しています。
ただし、これはあくまでも「このように記述することもできる」という話です。この両者を比較すると、論理積を使った前者のコードの方が直感的には理解しやすいでしょう。
条件分岐をネストさせる方法
既出の「ゴールド会員の場合に限り、購入金額が3000円以上になると特別優遇されて配送料は無料(それ以外は配送料は600円)」という仕様は、論理演算子ではなく、条件分岐のネストでも表現することができます。条件分岐のネストとは、ifブロックやelseブロックの中にさらにif文をネストして記述するというものです。
今回の例では、具体的には以下のようになります。
int deliveryFee;
if (customerType == GOLD_CUSTOMER) { //【1】ゴールド会員の場合
if (3000 <= totalPrice) { //【2】購入金額3000円以上の場合
deliveryFee = 0;
} else { //【3】購入金額3000円未満の場合
deliveryFee = 600;
}
} else { // 【4】一般会員の場合
deliveryFee = 600;
}
まず最初にif文【1】で、顧客種別(変数customerType)がゴールド会員かどうかの判定を行い、trueの場合は、ifブロック内に処理が進みます。次にifブロック内では、さらにif文【2】を記述してネストを作り、今度は購入金額(変数totalPrice)が3000円以上かどうかの判定を行います。判定の結果trueの場合は、「ゴールド会員であり、かつ、購入金額が3000円以上」という要件に合致するため、配送料(変数deliveryFee)は0円に決まります。もしゴールド会員であったとしても、購入金額が3000円未満の場合は、elseブロック【3】に進むことになるため、配送料は600円になります。
また、そもそも一般会員の場合は外側のif文【1】がfalseになるため、そのif文に対応したelseブロック【4】に処理が進み、同じように配送料は600円に決まります。
論理演算子かネストか
今度はもう少し仕様が複雑になり「ゴールド会員は、購入金額が3000円以上の場合は配送料は0円で、3000円未満の場合は600円。一方で一般会員は、購入金額が5000円以上の場合は配送料は300円で、5000円未満の場合は900円」という仕様を前提に考えます。
これを直交表で表すと、以下のようになります。
【表6-2-2】顧客種別*購入金額*配送料の直交表2
顧客種別 | 購入金額 | 配送料 |
---|---|---|
ゴールド会員 | 3000円以上 | 0円 |
ゴールド会員 | 3000円未満 | 600円 |
一般会員 | 5000円以上 | 300円 |
一般会員 | 5000円未満 | 900円 |
この仕様は、論理演算子でもネストでも、どちらでも表現することができます。
まず論理演算子を使用してコードを記述すると、以下のようになります。
int deliveryFee;
if (customerType == GOLD_CUSTOMER && 3000 <= totalPrice) {
deliveryFee = 0;
} else if (customerType == GOLD_CUSTOMER && totalPrice < 3000) {
deliveryFee = 600;
} else if (customerType == GENERAL_CUSTOMER && 5000 <= totalPrice) {
deliveryFee = 300;
} else {
deliveryFee = 900;
}
次に条件分岐のネストによってコードを記述すると、以下のようになります。
int deliveryFee;
if (customerType == GOLD_CUSTOMER) {
if (3000 <= totalPrice) {
deliveryFee = 0;
} else {
deliveryFee = 600;
}
} else { // 一般会員の場合
if (5000 <= totalPrice) {
deliveryFee = 300;
} else {
deliveryFee = 900;
}
}
さて、どちらのコードの方が良いでしょうか?
この両者を比較すると、論理演算子を使用したコード(前者)の方が、冗長な記述が多いことに気が付くでしょう。また前者のコードは、後から仕様変更となり、説明変数の種類が増えたり境界値が変更になったりするケースを考えると、必ずしも保守がしやすいとは言えません。その一方で、条件分岐のネスト(後者)では、ネストが深くなりすぎてしまうと、どこでどういった処理をしているのかが分かりにくいコードになり、可読性の低下を招く可能性があります。
このように複雑な条件をif文で表す場合、論理演算子を使うべきかネストさせるべきかは、一概に決めることはできません。説明変数の多さや、境界値が変更される可能性、ネストによる可読性の低下などを踏まえて、総合的な判断が必要です。
6.2.3 switch-case文
switch-case文とは
switch-case文とは、多岐分岐のための制御構文です。多岐分岐はif-else-if文でも実装可能ですが、分岐の条件が特定の値によって決まる場合は、switch-case文を利用すると効率的に実装することが可能です。if-else-if文では、論理値を返す条件式によって処理を多系統に分岐させますが、switch-case文では、1つの式または変数を指定し、その値に応じて処理を多系統に分岐させます。
フローチャートは以下のようになります。
【図6-2-4】switch-case文のフローチャート(多岐分岐)
switch-case文の構文は以下のとおりです。
switch (式) { // 変数のみでもOK
case ラベル1: // 第一分岐(case句)
....式の値がラベル1の場合の処理(1)....
break;
case ラベル2: // 第二分岐(case句)
....式の値がラベル2の場合の処理(2)....
break;
....case句を必要な分だけ記述....
default: // デフォルト分岐(default句)
....式の値がcase句に指定されたラベル以外の場合の処理(d)....
}
switch-case文では、まずswitchキーワードの後ろに( )
を記述し、式または変数を指定します。switchキーワードと( )
の間のスペースは任意ですが、可読性確保のためにスペースを1つ入れるのが一般的です。ここに指定できる式または変数の型は、int型、short型などの整数型や、String型、列挙型(チャプター15.1参照)に限定されます。
switch-case文のブロック内には、複数のcase句を記述することで、多岐分岐を表現します。case句は、caseキーワードとラベルおよび分岐処理のための命令文から構成されます。ラベルとは条件判定に使われる値で、式の値が一致したときに対応するcase句に処理が進みます。ラベルはカンマで区切って複数指定することができますが、複数指定することができるのはJava 12以降です。また複数のcase句で同一のラベルを指定すると、条件分岐ができなくなるためコンパイルエラーになります。ラベルの最後には:
を付与します。case句の最後にはbreakキーワードを記述し、このswitch-case文から抜けることを明記します。
case句は、第二分岐、第三分岐といった具合に、分岐数に応じて追加していきます。最後に、式の値が指定されたすべてのラベルと一致しなかった場合のデフォルト分岐を記述しますが、この分岐の実装は任意です。デフォルト分岐はdefaultキーワードを記述し、その後ろに処理を実装します。defaultキーワードの後ろに記述する命令文を、ここではdefault句と呼びます。
各分岐処理(case句)の最後には、基本的にはbreakキーワードを記述しますが、記述しなくてもコンパイルは通ります。ただしbreakキーワードを記述しないと、当該のcase句の処理が終わってもswitch-case文を抜けることはなく、次にbreakキーワードが登場するまで、以降のcase句とdefault句がすべて実行されますので、注意してください。
switch-case文の具体例(1)
それではswitch-case文による多岐分岐を、ECサイトの例をもとに具体的に説明します。ここでは顧客が一般会員、ゴールド会員、プラチナ会員、ダイヤモンド会員という4つの種別に分かれており、それぞれの種別に対して、int型の0、1、2、3というコード値が設定されているものとします。そして顧客種別に応じて、 一般会員またはゴールド会員の場合は配送料が900円、プラチナ会員の場合は600円、そしてダイヤモンド会員の場合は無料、という仕様を前提に考えます。
これをコードで表現すると、以下のようになります。
int deliveryFee = 0; //【1】
switch (customerType) { // int型変数
case 0, 1: // 一般会員またはゴールド会員を表すラベル
deliveryFee = 900;
break;
case 2: // プラチナ会員を表すラベル
deliveryFee = 600;
break;
case 3: // ダイヤモンド会員を表すラベル
deliveryFee = 0;
break;
}
ここでは、一般会員とゴールド会員を1つの分岐処理に束ねています。このコードを実行すると、顧客種別(int型変数customerType)の値に応じて処理が3系統に分岐され、それぞれで配送料が決定されます。
なおこのコードでは、取りうる顧客種別の値(0、1、2、3)が網羅されるように分岐を作っています。従って【1】で宣言した変数deliveryFeeは、このswitch文によって必ず何らかの値が決まりますが、それは開発者自身が保証しているだけであり、コンパイラでは「値の網羅性」を評価できません。そのため【1】において何らかの初期値を代入しておかないと、その後の処理でdeliveryFeeを参照しようとしたときに「初期化されていない可能性あり」としてコンパイルエラーが発生します。そのような理由から、ここでは初期値として0を代入しています。
上記コードでは、この4つ以外の値は取りえないという前提をおいているため、デフォルト分岐は実装していません。可能性としてこの4つ以外の値が変数customerTypeに格納されうる場合は、必要に応じてdefault句を記述し、エラー処理などを実装することになるでしょう。
switch-case文の具体例(2)
先に取り上げた例では、switch-case文にint型を指定しました。前述したようにswitch-case文には、int型などの整数型の他に、String型や列挙型を指定することができますが、ここではString型のケースを取り上げます。
先の例と同じように顧客が、一般会員、ゴールド会員、プラチナ会員、ダイヤモンド会員という4つの種別に分かれており、それぞれの種別に対して、文字列として、"GENERAL"、"GOLD"、"PLATINUM"、"DIAMOND"というラベルが割り当てられているものとします。そして顧客種別に応じて、配送料が変わるものとします。
これをコードで表現すると、以下のようになります。
int deliveryFee = 0;
switch (customerType) { // String型変数
case "GENERAL", "GOLD": // 一般会員またはゴールド会員を表すラベル
deliveryFee = 900;
break;
case "PLATINUM": // プラチナ会員を表すラベル
deliveryFee = 600;
break;
case "DIAMOND": // ダイヤモンド会員を表す値
deliveryFee = 0;
break;
}
ここでも、一般会員とゴールド会員を1つの分岐処理に束ねています。このコードを実行すると、顧客種別(String型変数customerType)の値に応じて処理が3系統に分岐され、仕様に応じて配送料が決まります。
switch文の利用方針
このチャプターでは、switch-case文にint型を指定するケースと、String型を指定するケースを取り上げました。
いずれのケースも、取りうる値を網羅する条件分岐が実装されることを、開発者自身が保証しなければなりません。その点、チャプター15.1で取り上げる列挙型を利用すると、取りうる値が網羅的に実装されているかをコンパイラにチェックさせることができます。
switch-case文では、堅牢性の観点から、なるべく列挙型と組み合わせて利用することを推奨します。
6.2.4 switch式
switch式とは
switch式は、多岐分岐をより簡潔に記述するための新機能として、Java 14でサポートされました。
switch式の構文は、以下のとおりです。
switch (式) {
case ラベル1 -> { // 第一分岐
....式の値がラベル1の場合の処理....
}
case ラベル2 -> { // 第二分岐
....式の値がラベル2の場合の処理....
}
....case句を必要な分だけ記述....
default -> { // デフォルト分岐
....式の値がcase句に指定されたラベル以外の場合の処理....
}
}
switch式の構文を見ると、switch-case文との違いがいくつかあることに気付くでしょう。まずcase句に指定するラベルの後ろですが、コロンではなく->
を記述します。この符号は「アロー演算子」と呼ばれるものです。そしてアロー演算子に{ }
でブロックを記述し、式の値がラベルに一致したときの分岐処理を実装します。case句の中が命令文1つだけの場合は、{ }
を省略することができます。
switch-case文では、case句の最後にbreakキーワードを記述し、switch-case文から抜けることを明示する必要がありましたが、switch式ではbreakキーワードを記述しなくても、以降の分岐処理に進むことはありません。
またswitch-case文ではdefault句の実装は任意でしたが、switch式でも同様です。特に式に列挙型を使用する場合など、式の取りうる値が網羅されていることが保証される場合は、default句を記述する意味はありません。
switch文よりもswitch式を利用する方が、コードを簡潔に記述することができるため、Java 14以降の環境では積極的に使用すると良いでしょう。
switch式の具体例
それではswitch式による多岐分岐を、ECサイトの例で考えてみましょう。ここでも顧客種別に応じて配送料が変わるものとします。具体的には、顧客種別に応じて、一般会員またはゴールド会員の場合は配送料が900円、プラチナ会員の場合は600円、そしてダイヤモンド会員の場合は無料、という仕様を前提に考えます。
これをswitch式を使って実装すると、以下のようになります。
int deliveryFee = 0;
switch (customerType) {
case 0, 1 -> deliveryFee = 900; //【1】
case 2 -> deliveryFee = 600; //【2】
case 3 -> { //【3】
System.out.println("ダイヤモンド会員の場合");
deliveryFee = 0;
}
default -> {
// エラー処理など
........
}
}
【1】~【2】は、case句の中の命令文が1つなので、{ }
を省略しています。また【3】は、case句の中に複数の命令文があるので、{ }
でブロックを記述しています。
上記コードでもデフォルト分岐は実装していませんが、必要に応じてdefault句を記述し、エラー処理などを実装してください。
値を返すswitch式
switchによる多岐分岐では、これまで見てきたように、分岐処理(case句)の中で任意の処理を行うことができます。ただし実際のJavaアプリケーションでは、分岐の中で行う処理は「何らかの値を決めること」というケースが大半を占めます。switch式では直接値を返すことができるため、このような処理を非常に簡潔に実装できます。
既出のコード(Main_Switch_3)と同じ仕様を、値を返すswitch式によって実装すると、以下のようになります。
int deliveryFee = switch (customerType) { //【1】
case 0, 1 -> 900; //【2】
case 2 -> 600; //【3】
case 3 -> { //【4】
System.out.println("ダイヤモンド会員の場合");
yield 0;
}
default -> { //【5】
// 例外の送出など
throw new IllegalArgumentException("不正な顧客種別");
}
}; //【6】
まず【1】にある通り、switch式の結果を、代入演算子によって直接変数(deliveryFee)に代入するように記述します。【2】~【3】のように、case句の中で行う処理が値を返すのみの場合は、アロー演算子の後ろに値を記述するだけで問題ありません。
一方で【4】のように、case句の中に複数の命令文がある場合は、アロー演算子の後ろに{ }
でブロックを記述し、ブロックの最後に返したい値をyieldキーワードによって指定します。
さて「値を返すswitch式」では、代入される変数が確実に初期化されるように、列挙型によって値の網羅性が保証されるケースを除き、default句の指定が必須になります【5】。このコードでは列挙型ではなく、int型の変数customerTypeによって分岐を行っているため、default句が必要です。default句では、yieldキーワードで値を指定するか、このコードのように例外の送出を行うことになるでしょう。
なお【6】の部分ですが、このコード全体は変数deliveryFeeへの代入を行う1つの式になるので、switch式の最後にセミコロンが必要になる点に、注意してください。
「値を返すswitch式」では、変数が確実に初期化されるようにdefault句の記述は必須です(ただし列挙型によって値の網羅性が保証されるケースは除く)。
6.2.5 三項演算子
三項演算子とは
三項演算子とは、3つのオペランドを取る特殊な演算子で、条件演算子とも呼ばれます。この演算子は、条件式の真偽(trueまたはfalse)によって、変数に代入する値を切り替えたい場合に使用します。if-else文でも同様の処理を記述できますが、三項演算子の方がより簡潔に記述することができます。
三項演算子の構文は、以下のとおりです。
条件式 ? 式1 : 式2
条件式の後ろに?
を記述し、その後ろに2つの式を:
で区切って記述します。条件式がtrueの場合は式1が評価され、また条件式がfalseの場合は式2が評価され、それぞれの値が返されます。
三項演算子の具体例
ここではif文の解説と同様に、ECサイトのアプリケーションを題材に考えてみましょう。具体的には、購入金額が10000円以上の場合は配送料は300円、10000円未満の場合は配送料は900円になる、という仕様を前提にします。
この仕様をif文で表現すると、以下のコード(既出のMain_If_1クラス)になります。
int deliveryFee;
if (10000 <= totalPrice) {
deliveryFee = 300;
} else {
deliveryFee = 900;
}
これと同じ処理を三項演算子を使って記述すると、以下のようになります。
int deliveryFee = 10000 <= totalPrice ? 300 : 900;
このコードでは、10000 <= totalPrice
が条件式に、300
がtrueの場合に評価される式に、900
がfalseの場合に評価される式に、それぞれ相当します。従って10000 <= totalPrice
がtrueの場合はdeliveryFeeは300円になり、falseの場合は900円になる、というわけです。if文によるコードと比べると、かなり簡潔に記述できている点が分かると思います。
三項演算子は、「条件の真偽に応じて変数の値を決める」という比較的よく登場するロジックを、簡潔に実装するための手法として覚えておくと良いでしょう。
このチャプターで学んだこと
このチャプターでは、以下のことを学びました。
- 条件分岐には、単純分岐や多岐分岐といった種類があること。
- if-else文による条件分岐の実装方法について。
- if-else-if文による多岐分岐の実装方法について。
- 2つ以上の変数による分岐では、論理演算子を用いるパターンや、分岐をネストするパターンがあること。
- switch-case文による多岐分岐の実装方法について。
- switch式による多岐分岐の特徴や、switch文との違いについて。
- 値を返すswitch式の記述方法や特徴について。
- 三項演算子による条件分岐の実装方法について。