- JAVA
Java三項演算子(条件演算子)の書き方|if elseを短くする例
三項演算子(条件演算子)とは、条件 ? 値1 : 値2 の形で「条件が true なら値1、false なら値2」を返す演算子です。 if else で5行かかる「どちらかの値を選ぶ」処理を1行で書けるのが特長で、Java の言語仕様では「条件演算子(Conditional Operator)? :」と呼ばれます。オペランド(演算の対象)を3つ取る演算子がこれ1つだけなので、「三項演算子」という呼び名が広く使われています。
この記事では、if else と三項演算子の書き換え前後を並べて示し、代入・return・引数・文字列連結での使用例を実行結果つきで紹介します。さらに、Integer と int を混ぜて NullPointerException になる例、1 を選んだはずが 1.0 と表示される数値昇格の例、文字列連結で括弧を忘れた例を実際に再現し、ネストするときの整形ルール、Java 14 以降の switch 式や Optional との使い分け早見表までまとめました。コードはすべて OpenJDK 21.0.10 で java ファイル名.java として実行した結果です。
三項演算子の早見表
| やりたいこと | 書き方 | 結果 |
|---|---|---|
| 基本形 | 条件 ? trueのときの値 : falseのときの値 |
どちらか一方の値 |
| 代入 | String r = score >= 60 ? "合格" : "再挑戦"; |
score が72なら 合格 |
| return | return n >= 0 ? n : -n; |
絶対値 |
| 引数 | String.format("%d item%s", n, n == 1 ? "" : "s") |
1 item / 3 items |
| 文字列連結 | "在庫: " + (stock > 0 ? stock + "個" : "なし") |
丸括弧で囲むのがポイント |
| null の既定値 | name != null ? name : "(名前なし)" |
null なら (名前なし) |
| 3つ以上に分ける | a ? x : b ? y : z |
右から結び付く(a ? x : (b ? y : z)) |
| 型をそろえる | flag ? 1 : 2.0 → 1.0 |
数値は大きい型に昇格する |
| 使えること | 使えないこと |
|---|---|
| 値を選んで、代入・return・引数に渡す | 条件 ? 処理A() : 処理B(); と文として単独で書く(コンパイルエラー) |
| 式の中に埋め込む | 戻り値が void のメソッドを値として置く(コンパイルエラー) |
| ネストして3つ以上に分ける | false 側(: 以降)を省略する |
三項演算子は「値を選ぶ」ためのもの、if else は「処理を分ける」ためのものと覚えておくと、使い分けに迷いません。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Java三項演算子(条件演算子)の書き方|if elseを短くする例」
三項演算子の基本構文とif elseからの書き換え
構文は次の形です。
条件式 ? 式1 : 式2
| 部分 | 内容 |
|---|---|
| 条件式 | boolean(または Boolean)になる式。score >= 60 など |
? |
「もし true なら」の区切り |
| 式1 | 条件式が true のときに使われる値 |
: |
「そうでなければ」の区切り |
| 式2 | 条件式が false のときに使われる値 |
同じ処理を if else と三項演算子で並べてみます。次のコードは IfVsTernary.java として保存し、java IfVsTernary.java でそのまま実行できます。
public class IfVsTernary {
public static void main(String[] args) {
int score = 72;
// if else で書いた場合(5行)
String result1;
if (score >= 60) {
result1 = "合格";
} else {
result1 = "再挑戦";
}
// 三項演算子で書いた場合(1行)
String result2 = score >= 60 ? "合格" : "再挑戦";
System.out.println(result1);
System.out.println(result2);
}
}
実行結果(OpenJDK 21.0.10):
合格
合格
書き換えの手順は3ステップです。
- if と else の両方が「同じ変数に値を入れているだけ」(または両方が return しているだけ)であることを確かめる
変数 = 条件 ? ifの中の値 : elseの中の値;の形に並べ替える- 1行が長くなったら、
?と:の前で改行する
| 比べる点 | if else | 三項演算子 |
|---|---|---|
| 種類 | 文(値を返さない) | 式(値を返す) |
| 行数 | 4〜5行 | 1行 |
| 宣言と同時の初期化 | 宣言と代入が分かれる | 1行で書ける(final にしやすい) |
| 複数の処理を書く | 書ける | 書けない(値を1つ選ぶだけ) |
| else なし | 書ける | 書けない |
| 向いている場面 | 処理の分岐、分岐の中身が複数行 | 短い値の選択 |
三項演算子の使用例8パターン(代入・return・引数・文字列連結)
よく使う場面を1つのプログラムにまとめました。
public class Usage {
// 2. return で使う
static String grade(int score) {
return score >= 60 ? "合格" : "再挑戦";
}
static int abs(int n) {
return n >= 0 ? n : -n;
}
public static void main(String[] args) {
// 1. 代入で使う(final な変数も1行で初期化できる)
int a = 3, b = 9;
final int max = a > b ? a : b;
System.out.println("1: max=" + max);
// 2. return で使う
System.out.println("2: " + grade(45) + " / " + abs(-8));
// 3. メソッドの引数で使う
int count = 1;
System.out.println(String.format("3: %d item%s", count, count == 1 ? "" : "s"));
count = 3;
System.out.println(String.format("3: %d item%s", count, count == 1 ? "" : "s"));
// 4. 文字列連結の中で使う(全体を丸括弧で囲む)
int stock = 0;
System.out.println("4: 在庫: " + (stock > 0 ? stock + "個" : "なし"));
// 5. null のときの既定値
String name = null;
String shown = name != null ? name : "(名前なし)";
System.out.println("5: " + shown);
// 6. 複合代入の右辺
int point = 10;
point += point > 5 ? 1 : 2;
System.out.println("6: " + point);
// 7. ラムダ式の本体
java.util.function.IntUnaryOperator sign = v -> v > 0 ? 1 : v < 0 ? -1 : 0;
System.out.println("7: " + sign.applyAsInt(-5) + " " + sign.applyAsInt(0) + " " + sign.applyAsInt(7));
// 8. 選ばれなかった側の式は評価されない
int[] calls = {0};
int value = true ? 10 : calls[0]++;
System.out.println("8: value=" + value + " calls=" + calls[0]);
}
}
実行結果:
1: max=9
2: 再挑戦 / 8
3: 1 item
3: 3 items
4: 在庫: なし
5: (名前なし)
6: 11
7: -1 0 1
8: value=10 calls=0
各パターンのif else版との対比
| 番号 | 三項演算子 | if else で書いた場合 |
|---|---|---|
| 1 代入 | final int max = a > b ? a : b; |
int max; if (a > b) { max = a; } else { max = b; } |
| 2 return | return n >= 0 ? n : -n; |
if (n >= 0) { return n; } else { return -n; } |
| 3 引数 | format("%d item%s", n, n == 1 ? "" : "s") |
先に String suffix; を if else で決めてから渡す |
| 4 連結 | "在庫: " + (stock > 0 ? stock + "個" : "なし") |
先に String text; を if else で決めてから連結する |
| 5 既定値 | name != null ? name : "(名前なし)" |
if (name == null) { shown = "(名前なし)"; } else { shown = name; } |
引数や連結の途中など、「文を書けない場所」で値を切り替えられるのが、三項演算子ならではの利点です。if else だと一時変数が1つ必要になる場面で、変数を増やさずに済みます。
8番目の結果 calls=0 は、選ばれなかった側の式が実行されないことを示しています。条件が true なので calls[0]++ は一度も評価されていません。これを利用した name != null ? name.length() : 0 のような書き方では、name が null のときに name.length() が呼ばれないため、安全に書けます。
文字列連結では三項演算子を丸括弧で囲む
三項演算子は、演算子の中で優先順位がとても低い(代入の1つ上)ため、+ や != のほうが先に計算されます。文字列連結の中で括弧を付けないと、意図と違う範囲が条件になります。
public class Paren {
public static void main(String[] args) {
String s = null;
// 括弧なし:("値=" + s) != null ? "あり" : "なし" と解釈される
System.out.println("値=" + s != null ? "あり" : "なし");
// 括弧あり:意図どおり
System.out.println("値=" + (s != null ? "あり" : "なし"));
}
}
実行結果:
あり
値=なし
括弧なしの1行目は、s が null なのに「あり」と表示され、しかも先頭の 値= が消えています。"値=" + s が先に連結されて "値=null" という文字列になり、それが null でないので「あり」が選ばれた、という流れです。コンパイルエラーにならず、実行しても例外が出ないため、出力を見るまで気づきにくいパターンです。
比較する相手が数値の場合は、コンパイルの段階で知らせてくれます。
int n = 5;
System.out.println("n is " + n > 3 ? "big" : "small");
BadTypes.java:5: error: bad operand types for binary operator '>'
System.out.println("n is " + n > 3 ? "big" : "small");
^
first type: String
second type: int
"n is " + n が先に計算されて String になり、String と int を > で比べようとしてエラーになっています。
| 優先順位(高い順) | 演算子 |
|---|---|
| 高い | * / % |
| ↓ | + -(文字列連結の + を含む) |
| ↓ | < > <= >= |
| ↓ | == != |
| ↓ | && |
| ↓ | || |
| ↓ | ? :(三項演算子) |
| 低い | = += などの代入 |
「三項演算子を他の式の中に入れるときは、全体を丸括弧で囲む」と決めておくと、優先順位を思い出す必要がなくなります。条件式そのもの(score >= 60 など)には括弧がなくても正しく動きますが、(score >= 60) ? ... : ... と囲んで読みやすくする書き方もよく使われます。
数値の型が変わる:1のはずが1.0と表示される例
三項演算子は式なので、全体として1つの型を持ちます。? の後ろと : の後ろで型が違うとき、数値同士なら大きいほうの型にそろえられます(数値昇格)。これが、if else にはない三項演算子特有の動きです。
public class Promotion {
public static void main(String[] args) {
boolean flag = true;
// 1. int と double を混ぜると、全体が double になる
System.out.println("1: " + (flag ? 1 : 2.0));
Object o = flag ? 1 : 2.0;
System.out.println("2: " + o + " " + o.getClass().getSimpleName());
// 3. if else なら、代入した値の型のまま
Object p;
if (flag) { p = 1; } else { p = 2.0; }
System.out.println("3: " + p + " " + p.getClass().getSimpleName());
// 4. ラッパークラス同士でも数値として昇格する
Integer wi = 1;
Double wd = 2.0;
System.out.println("4: " + (flag ? wi : wd));
// 5. Object にキャストすれば、そのままの型で扱われる
Object q = flag ? (Object) 1 : (Object) 2.0;
System.out.println("5: " + q + " " + q.getClass().getSimpleName());
// 6. 数値と文字列のように昇格できない組み合わせは、そのまま
Object r = flag ? 1 : "two";
System.out.println("6: " + r + " " + r.getClass().getSimpleName());
// 7. char と int
char c = 'a';
int i = 0;
System.out.println("7: " + (flag ? c : 0)); // 0 は定数 → char のまま
System.out.println("8: " + (flag ? c : i)); // i は変数 → int に昇格
// 9. int と long
Object l = flag ? 1 : 2L;
System.out.println("9: " + l.getClass().getSimpleName());
}
}
実行結果:
1: 1.0
2: 1.0 Double
3: 1 Integer
4: 1.0
5: 1 Integer
6: 1 Integer
7: a
8: 97
9: Long
条件は true で 1 を選んでいるのに、表示は 1.0 です。 選ばれなかった側の 2.0 が double なので、式全体の型が double に決まり、1 が 1.0 に変換されています。同じ内容を if else で書いた3番は 1 Integer のままで、ここが両者の違いです。
? の後ろ |
: の後ろ |
式全体の型 | 実行結果 |
|---|---|---|---|
int(1) |
double(2.0) |
double |
1.0 |
Integer |
Double |
double |
1.0 |
int(1) |
long(2L) |
long |
Long として扱われる |
char('a') |
int の定数(0) |
char |
a |
char('a') |
int の変数(i) |
int |
97 |
int(1) |
String("two") |
共通の親の型 | 1 Integer のまま |
(Object) 1 |
(Object) 2.0 |
Object |
1 Integer のまま |
Java 言語仕様(Java SE 21 版の 15.25 節)で確認したところ、2つのオペランドがどちらも数値型のときは二項数値昇格(binary numeric promotion)が適用されること、片方が byte・short・char で、もう片方がその型で表せる int の定数式であれば前者の型になること、が定められています。7番と8番の違い(0 という定数なら a、変数 i なら 97)は、この規則どおりの結果です。
整数と小数を出し分けたいときは、三項演算子の2つの値の型をそろえる(例:どちらも String にする)か、if else で書くのが分かりやすい対処です。
Integerとintの混在でNullPointerExceptionになる例
数値昇格と同じ仕組みで、もう1つ気をつけたい動きがあります。Integer(ラッパークラス)と int(基本型)を混ぜると、Integer 側が自動的に int に変換(アンボクシング)され、その値が null だと例外になります。
public class Npe {
public static void main(String[] args) {
Integer stock = null; // 在庫数が未登録
boolean found = true;
Integer shown = found ? stock : 0;
System.out.println(shown);
}
}
実行結果(java Npe.java):
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because "<local1>" is null
at Npe.main(Npe.java:6)
代入先は Integer なので null をそのまま入れられそうに見えますが、6行目で NullPointerException になります。 stock(Integer)と 0(int)が並んでいるため、式全体の型が int に決まり、stock に対して intValue() が呼ばれるからです。メッセージの Cannot invoke "java.lang.Integer.intValue()" がそれを示しています。
<local1> は変数名の代わりの表示です。単一ファイル実行ではデバッグ情報なしでコンパイルされるためで、javac -g Npe.java でコンパイルしてから実行すると、次のように変数名が表示されました。
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because "stock" is null
at Npe.main(Npe.java:6)
Java 言語仕様の 15.25 節にも、片方が int、もう片方が対応するラッパークラスのときは、ラッパー側にアンボクシング変換が適用される旨が書かれています。
直し方4通り
import java.util.Objects;
import java.util.Optional;
public class NpeFix {
public static void main(String[] args) {
Integer stock = null;
boolean found = true;
// 直し方1:2つの型を Integer にそろえる
Integer a = found ? stock : Integer.valueOf(0);
System.out.println("1: " + a);
// 直し方2:if else で書く
Integer b;
if (found) { b = stock; } else { b = 0; }
System.out.println("2: " + b);
// 直し方3:null を先に確かめてから int にする
int c = stock != null ? stock : 0;
System.out.println("3: " + c);
// 直し方4:null のときの既定値を返すメソッドを使う
System.out.println("4: " + Objects.requireNonNullElse(stock, 0));
System.out.println("5: " + Optional.ofNullable(stock).orElse(0));
}
}
実行結果:
1: null
2: null
3: 0
4: 0
5: 0
| 目的 | 書き方 | 結果 |
|---|---|---|
| null を null のまま受け取りたい | 両方を Integer にそろえる(Integer.valueOf(0)) |
null |
| null を null のまま受け取りたい | if else で書く | null |
| null のときは 0 にしたい | stock != null ? stock : 0 |
0 |
| null のときは 0 にしたい | Objects.requireNonNullElse(stock, 0)(Java 9 以降) |
0 |
| null のときは 0 にしたい | Optional.ofNullable(stock).orElse(0) |
0 |
メソッドの戻り値が Integer で null を返し得る場合も同じです。flag ? findStock(name) : 0 のように 「null になり得るラッパー型」と「基本型のリテラル」を三項演算子で並べたら、型をそろえるか null を先に確かめる、と覚えておくと防げます。
三項演算子をネストするときの整形ルール
3つ以上に分けたいときは、: の後ろにもう1つ三項演算子を続けます。1行に詰めると読みにくいので、条件ごとに改行し、: を行頭にそろえる書き方がよく使われます。
public class Nest {
// ネストした三項演算子(条件ごとに改行して縦にそろえる)
static String rank(int score) {
return score >= 90 ? "A"
: score >= 70 ? "B"
: score >= 50 ? "C"
: "D";
}
// 同じ処理を if else で
static String rankIf(int score) {
if (score >= 90) return "A";
if (score >= 70) return "B";
if (score >= 50) return "C";
return "D";
}
public static void main(String[] args) {
for (int score : new int[]{95, 75, 55, 30}) {
System.out.println(score + " → " + rank(score) + " / " + rankIf(score));
}
// 右結合:a ? b : c ? d : e は a ? b : (c ? d : e)
int k = 2;
String word = k == 1 ? "one" : k == 2 ? "two" : "many";
System.out.println(word);
}
}
実行結果:
95 → A / A
75 → B / B
55 → C / C
30 → D / D
two
三項演算子は右結合です。Java 言語仕様の 15.25 節にも、a ? b : c ? d : e は a ? b : (c ? d : e) と同じ意味になると書かれています。つまり上から順に条件を確かめ、最初に true になった行の値が選ばれます。if / else if / else と同じ読み方ができるので、縦にそろえた形なら流れを追いやすくなります。
ネストの整形ルール
| ルール | 理由 |
|---|---|
1行に1条件。: を行頭にそろえる |
「条件 → 値」の対応が表のように読める |
ネストは : の後ろ(false 側)だけに続ける |
? の後ろ(true 側)にネストすると、どの : と対応するか追いにくい |
| 最後の行は条件なしの既定値にする | else に当たる値がひと目で分かる |
| 各行の値は同じ型にそろえる | 前の節の数値昇格やアンボクシングを避けられる |
| 段数は2〜3段までを目安にする | それ以上は if 文、switch 式、Map などへの置き換えを検討する |
値の側に副作用のある処理(i++ やメソッドでの更新)を置かない |
どちらが実行されるか読み取りにくくなる |
true 側にネストした形と、整えた形を並べます(説明用の断片で、単体では実行していません)。
// 読み取りにくい形:true 側にネストし、1行に詰めている
String fee = member ? age < 18 ? "A" : "B" : "C";
// 整えた形1:false 側だけに続け、条件ごとに改行する
String fee = !member ? "C"
: age < 18 ? "A"
: "B";
// 整えた形2:内側をメソッドに切り出す
String fee = member ? memberFee(age) : "C";
switch式・Optional・if文との使い分け
Java 14 で正式に導入された switch 式は、三項演算子と同じく値を返す式として使えます。1つの値で3つ以上に分けるなら、switch 式のほうがすっきり書けます。
import java.util.Optional;
public class SwitchOptional {
enum Status { OPEN, DOING, DONE }
// 三項演算子のネスト
static String labelTernary(Status s) {
return s == Status.OPEN ? "未着手"
: s == Status.DOING ? "作業中"
: "完了";
}
// switch 式(Java 14 以降)
static String labelSwitch(Status s) {
return switch (s) {
case OPEN -> "未着手";
case DOING -> "作業中";
case DONE -> "完了";
};
}
// 複数の値をまとめる
static String rank(int score) {
return switch (score / 10) {
case 10, 9 -> "A";
case 8, 7 -> "B";
case 6, 5 -> "C";
default -> "D";
};
}
public static void main(String[] args) {
System.out.println(labelTernary(Status.DOING) + " / " + labelSwitch(Status.DOING));
System.out.println(rank(95) + rank(75) + rank(55) + rank(30));
// null のときの既定値:三項演算子と Optional
String nick = null;
String t = nick != null ? nick.toUpperCase() : "GUEST";
String o = Optional.ofNullable(nick).map(String::toUpperCase).orElse("GUEST");
System.out.println(t + " / " + o);
nick = "taro";
System.out.println((nick != null ? nick.toUpperCase() : "GUEST")
+ " / " + Optional.ofNullable(nick).map(String::toUpperCase).orElse("GUEST"));
}
}
実行結果:
作業中 / 作業中
ABCD
GUEST / GUEST
TARO / TARO
enum を switch 式で分けると、すべての定数を書いていれば default が不要になり、あとで定数を追加したときにコンパイラが書き漏れを知らせてくれます。三項演算子のネストでは最後の : "完了" が「それ以外すべて」を受けるため、定数が増えても気づけません。この点が switch 式を選ぶ大きな理由になります。
使い分け早見表
| 状況 | おすすめ | 例 |
|---|---|---|
| 2つの値のどちらかを選ぶ | 三項演算子 | score >= 60 ? "合格" : "再挑戦" |
| 範囲の条件で3〜4つに分ける | 三項演算子のネスト(縦にそろえる)または if / else if | score >= 90 ? "A" : score >= 70 ? "B" : "C" |
| 1つの値(enum・文字列・整数)で3つ以上に分ける | switch 式 | switch (status) { case OPEN -> ...; } |
| null のときの既定値だけ決めたい | 三項演算子、または Objects.requireNonNullElse |
name != null ? name : "(名前なし)" |
| null チェックの後に変換を重ねたい | Optional | Optional.ofNullable(x).map(...).orElse(...) |
| 分岐の中で複数の処理をする | if else | ログ出力と代入を両方行う、など |
| else が不要(条件を満たすときだけ処理) | if | if (x > 0) { count++; } |
| 戻り値のない処理(void)を切り替える | if else | if (ok) save(); else retry(); |
| boolean をそのまま返す | 条件式だけ | return age >= 18; |
Optional は「値がないかもしれない」ことを型で表す仕組みで、map で変換を重ねられるのが特長です。変換が1段だけなら三項演算子のほうが短く、2段以上重なるなら Optional が読みやすい、というのが目安です。
つまずきやすい書き方と実際のエラー文
文として単独では書けない
三項演算子は値を返す式なので、処理の切り替えだけを目的に単独の文として書くとコンパイルエラーになります。
int n = 5;
n > 3 ? System.out.println("big") : System.out.println("small");
NotStatement.java:4: error: not a statement
n > 3 ? System.out.println("big") : System.out.println("small");
^
1 error
Java 言語仕様の 15.25 節でも、戻り値が void のメソッド呼び出しを2番目・3番目のオペランドに置くことはコンパイルエラーと定められています。直し方は2通りです。
// 直し方1:値を選んでから、1回だけ出力する
System.out.println(n > 3 ? "big" : "small");
// 直し方2:処理を分けたいなら if else
if (n > 3) {
System.out.println("big");
} else {
System.out.println("small");
}
代入先の型に合わない値を置く
int n = 5;
String s = n > 3 ? "big" : 0;
BadTypes.java:4: error: incompatible types: bad type in conditional expression
String s = n > 3 ? "big" : 0;
^
int cannot be converted to String
2つの値は、どちらも代入先の型に合っている必要があります。 条件が true で "big" が選ばれる場合でも、false 側の 0 が String に変換できないためエラーになります。"0" と文字列にするか、String.valueOf(0) で変換します。
true / false をそのまま返している
public class Redundant {
public static void main(String[] args) {
int age = 20;
boolean adult1 = age >= 18 ? true : false; // 冗長
boolean adult2 = age >= 18; // これで十分
System.out.println(adult1 + " " + adult2);
boolean off1 = adult1 ? false : true; // 冗長
boolean off2 = !adult1; // これで十分
System.out.println(off1 + " " + off2);
}
}
実行結果:
true true
false false
条件式そのものが boolean の値を持っているので、? true : false は付けなくても同じ結果になります。逆にしたいときは ! を使います。
症状別チェック表
| 症状 | 理由 | 直し方 |
|---|---|---|
error: not a statement |
三項演算子を単独の文として書いた | 値を選んでから渡す、または if else |
error: incompatible types: bad type in conditional expression |
2つの値のどちらかが代入先の型に合わない | 2つの値の型をそろえる |
error: bad operand types for binary operator '>' |
文字列連結が先に計算された | 三項演算子全体を丸括弧で囲む |
| 連結した文字列の前半が消える | 同上(!= や == の場合はエラーにならない) |
三項演算子全体を丸括弧で囲む |
1 のはずが 1.0 と表示される |
int と double が混在し、double に昇格した | 型をそろえる、または if else |
文字のはずが 97 と表示される |
char と int の変数が混在し、int に昇格した | (char) でキャストするか、両方 char にする |
NullPointerException(intValue()) |
Integer と int が混在し、null がアンボクシングされた | 両方ラッパー型にそろえる、または null を先に確かめる |
| ネストの結果が想定と違う | true 側にネストして : の対応を取り違えた |
false 側だけに続け、条件ごとに改行する |
よくある質問
Q. 三項演算子と条件演算子は同じものですか?
A. 同じものです。Java 言語仕様での名前は「条件演算子(Conditional Operator)? :」で、オペランドを3つ取ることから「三項演算子」とも呼ばれます。Java で3つのオペランドを取る演算子はこれだけなので、どちらの名前でも通じます。
Q. 三項演算子はif elseより速いですか? A. 速度を理由に選ぶものではありません。今回は速度の計測を行っていませんが、どちらも「条件を1回評価して一方を選ぶ」処理であり、選ぶ基準は読みやすさです。値を1つ選ぶだけなら三項演算子、処理を分けるなら if else が向いています。
Q. else(: の後ろ)を省略できますか? A. 省略できません。三項演算子は必ず値を返す式なので、true のときと false のときの両方の値が必要です。条件を満たすときだけ処理したい場合は if 文を使います。
Q. 三項演算子はネストしてよいですか?
A. 条件ごとに改行して : を行頭にそろえ、false 側だけに続ける形なら、if / else if と同じ読み方ができます。2〜3段を超える場合や、1つの値で分ける場合は switch 式のほうが読みやすくなります。チームのコーディング規約で決まりがある場合は、それに合わせます。
まとめ
- 三項演算子は
条件 ? trueの値 : falseの値。if else で同じ変数に代入しているだけ・return しているだけの箇所を1行にできる - 値を選ぶ式であり、文としては書けない。void メソッドの切り替えや else なしの分岐は if 文で書く
- 文字列連結などの式の中では、三項演算子全体を丸括弧で囲む。優先順位が低いため、括弧がないと
+が先に計算される - 数値の型が違うと大きい型に昇格する(
flag ? 1 : 2.0は1.0)。if else とは結果が変わる Integerとintを混ぜると、null のアンボクシングでNullPointerExceptionになる。型をそろえるか、null を先に確かめる- ネストは false 側だけに続け、条件ごとに改行して
:をそろえる。段数は2〜3段までが目安 - 1つの値で3つ以上に分けるなら switch 式、null からの変換を重ねるなら Optional が読みやすい
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Java三項演算子(条件演算子)の書き方|if elseを短くする例」
株式会社RJCでは、三項演算子のような基本文法の使いどころを仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。