信頼度ランク
| S | 公式ソース確認済み |
| A | 成功実績多数・失敗例少数 |
| B | 賛否両論 |
| C | 動作未確認・セキュリティリスク高 |
| Z | 個人所感 |
演算子の評価順序と落とし穴 — i++とi++の違い・短絡評価・整数演算の罠
前置/後置インクリメントの評価タイミングの違い、&&と&の短絡評価の仕組み、整数除算の切り捨て、オーバーフローの挙動を試験頻出パターンとともに解説。
一言結論
i++は「今の値を使ってからインクリメント」、++iは「インクリメントしてから使う」。&&と||は短絡評価するが&と|はしない。整数除算はゼロ方向への切り捨てでオーバーフローは黙って折り返す。
前置と後置インクリメントの違い
インクリメント演算子++には2種類ある:
int i = 5;
System.out.println(i++); // 5(今の値を返してからインクリメント)
System.out.println(i); // 6
int j = 5;
System.out.println(++j); // 6(インクリメントしてから値を返す)
System.out.println(j); // 6
後置(i++):式の評価では「今の値」を返し、その後インクリメントする
前置(++i):先にインクリメントし、インクリメント後の値を式の評価で使う
単独で使うだけなら差はないが、式の中で使うときに差が出る:
int a = 3;
int b = a++ * 2;
// a++ は「3を使ってからaを4にする」
// b = 3 * 2 = 6
// a = 4
System.out.println(a); // 4
System.out.println(b); // 6
int c = 3;
int d = ++c * 2;
// ++c は「cを4にしてから4を使う」
// d = 4 * 2 = 8
// c = 4
System.out.println(c); // 4
System.out.println(d); // 8
式の中で複数回使うケース
int i = 0;
int result = i++ + i++;
これはどうなるか。左から右に評価される:
i=0の状態で i++ を評価 → 0を返してiを1にする
i=1の状態で i++ を評価 → 1を返してiを2にする
result = 0 + 1 = 1
i = 2
System.out.println(result); // 1
System.out.println(i); // 2
試験ではこういった「i++を複数回使うコード」が頻出だ。ポイントは「後置は今の値を返して後でインクリメント」を一つずつ丁寧に追うこと。
デクリメント--も同じルールだ:
int x = 5;
int y = x-- - --x;
// x-- : 5を返してxを4にする
// --x : xを3にして3を返す
// y = 5 - 3 = 2
// x = 3
代入式は値を返す
Javaでは代入(=)も式として値を返す:
int a;
int b = (a = 5) + 3;
// a = 5 → aに5を代入し、値として5を返す
// b = 5 + 3 = 8
System.out.println(a); // 5
System.out.println(b); // 8
これを使って複数変数を一度に初期化できる:
int a, b, c;
a = b = c = 0;
// c = 0(cに0を代入し0を返す)
// b = 0(bに0を代入し0を返す)
// a = 0
// 右から左への代入
代入演算子は右結合(右から左に評価される)だ。
短絡評価(Short-Circuit Evaluation)
&&と||は「短絡評価」を行う:
&&(AND):左辺がfalseなら、右辺を評価しない
int x = 5;
boolean result = (x > 10) && (++x > 0);
// (x > 10) → false
// falseなら結果はfalse確定。右辺は評価しない
System.out.println(result); // false
System.out.println(x); // 5(右辺の ++x が実行されていない!)
||(OR):左辺がtrueなら、右辺を評価しない
int y = 5;
boolean r = (y < 10) || (++y > 0);
// (y < 10) → true
// trueなら結果はtrue確定。右辺は評価しない
System.out.println(r); // true
System.out.println(y); // 5(右辺の ++y が実行されていない!)
これが試験の罠になる。「++が実行されているように見えて実は実行されていない」というパターンだ。
&と|は短絡しない:
int z = 5;
boolean b = (z > 10) & (++z > 0);
// (z > 10) → false でも右辺は必ず評価する
// (++z > 0) → zが6になる
System.out.println(b); // false
System.out.println(z); // 6(右辺が必ず評価される)
&と|は「両辺を必ず評価する」。boolean同士で使う場面は少ないが(ビット演算と混同しやすいため)、試験では区別を問われる。
整数除算は「ゼロ方向への切り捨て」
System.out.println(7 / 2); // 3(切り捨て)
System.out.println(-7 / 2); // -3(ゼロ方向)
System.out.println(7 / -2); // -3(ゼロ方向)
System.out.println(-7 / -2); // 3
「切り捨て」というとマイナスのときに間違えやすい。-7 / 2 = -3.5の絶対値を切り捨てると-3だ(-4ではない)。Math.floor(-3.5) = -4とは違うので注意。
剰余(%)もゼロ方向:
System.out.println(7 % 2); // 1
System.out.println(-7 % 2); // -1(符号は左辺に依存)
System.out.println(7 % -2); // 1(符号は左辺に依存)
System.out.println(-7 % -2); // -1
剰余の符号は「左辺(被除数)の符号と同じ」と覚えるといい。
整数のゼロ除算は例外:
int x = 5 / 0; // ❌ ArithmeticException: / by zero
浮動小数点のゼロ除算は例外ではなくInfinityやNaNになる:
System.out.println(5.0 / 0.0); // Infinity
System.out.println(-5.0 / 0.0); // -Infinity
System.out.println(0.0 / 0.0); // NaN
オーバーフローは黙って折り返す
int max = Integer.MAX_VALUE; // 2147483647
System.out.println(max + 1); // -2147483648(!)
Integer.MAX_VALUE + 1はエラーにならない。ビット列が「折り返し」てInteger.MIN_VALUEになる:
int の最大値: 01111111 11111111 11111111 11111111 = 2147483647
+1すると: 10000000 00000000 00000000 00000000 = -2147483648(2の補数表現)
Javaは整数のオーバーフローを検出せず例外を投げない。計算は黙って間違った値になる。これは言語仕様の設計判断(常に検出するとパフォーマンスが落ちる)だ。
大きな数を扱う場合はlongを使うか、java.math.BigIntegerを使う。
演算子の優先順位
試験でよく問われるもの:
// 乗除は加減より先
int a = 2 + 3 * 4; // 2 + 12 = 14(3*4が先)
// 単項マイナスとインクリメント
int b = -i++; // -(i++) であって (-i)++ ではない
// 後置++の優先度は単項演算子より高い
// 比較より算術が先
boolean c = 1 + 2 == 3; // (1+2) == 3 → true
// instanceof の優先度
boolean d = "hello" instanceof String && true; // (("hello" instanceof String) && true)
全体の優先順位表を丸暗記するより「分からないときは()で明示する」のが実用的だ。試験では典型的なパターンだけ押さえれば十分。
まとめ
後置 i++ = 今の値を式で使い、その後インクリメント
前置 ++i = 先にインクリメントし、インクリメント後の値を式で使う
代入式 = 値を返す(a = 5 は「5」を返す)。右結合
短絡評価:
&& : 左がfalse → 右は実行しない
|| : 左がtrue → 右は実行しない
& : 両辺を必ず実行
| : 両辺を必ず実行
整数除算 = ゼロ方向への切り捨て(-7/2 = -3。-4ではない)
剰余の符号 = 左辺(被除数)と同じ
整数/0 = ArithmeticException
浮動小数/0 = Infinity / NaN(例外なし)
オーバーフロー = 黙って折り返す(例外なし)