複合代入演算子の全体像
複合代入演算子は「計算して、その結果を同じ変数に代入する」操作を一行で書ける記法です。x += y は x = x + y、x *= y は x = x * y と同義で、読みやすさと意図の明確さを両立できます。代入は右辺が先に評価され、その結果を左辺へ反映します。複合代入は「更新処理」を端的に表すため、ループや累積、フラグ操作で多用します。
算術系の複合代入(+=, -=, *=, /=, %=)
+= は加算して代入、-= は減算して代入、*= は乗算して代入、/= は除算して代入、%= は剰余を計算して代入します。整数に対する /= は小数切り捨てになり、%= は負の数のとき符号に注意が必要です。
int n = 10;
n += 3; // 13
n -= 2; // 11
n *= 4; // 44
n /= 5; // 8(整数の割り算は切り捨て)
n %= 3; // 2(余り)
Java小数を伴う更新では、意図した型へ変換してから複合代入すると安全です。例えば割引率を掛けるときは double を使い、丸めは表示側で行うと設計が安定します。
double price = 1999.5;
price *= 0.9; // 10% 引き
System.out.printf("%.2f%n", price);// 表示は小数2桁に丸め
Javaビット・論理の複合代入(&=, |=, ^=, <<=, >>=, >>>=)
ビット演算の複合代入は、フラグ管理や低レベル操作に向いています。|= は付与、&= は除去(組み合わせに ~ を使う)、^= はトグル、<<= は左シフト、>>= は符号付き右シフト、>>>= はゼロ埋め右シフトです。
int READ = 0b0001, WRITE = 0b0010, EXEC = 0b0100;
int perm = 0;
perm |= READ; // READ を付与
perm |= WRITE; // WRITE を付与
perm &= ~READ; // READ を除去(NOT と AND の組み合わせ)
perm ^= EXEC; // EXEC をトグル(ON/OFF 切り替え)
Javaブール型に対する &= と |= は「論理 AND/OR(非短絡)」として動作します。^= は「論理 XOR」で、真偽を反転するトグルに応用できます。
boolean enabled = true;
enabled ^= true; // false(XOR:片方だけ真なら真 → 反転になる)
Javaシフトはビット列の位置を動かすため、マスクやエンコード/デコードに使います。
int x = 0b0001;
x <<= 3; // 0b1000
x >>= 1; // 0b0100(符号付き右シフト)
Java型とキャストの仕様(重要ポイントの深掘り)
複合代入は「左辺の型へ暗黙キャスト」されるのが特徴です。通常の代入計算では中間結果が int になるため short/byte に戻せずコンパイルエラーになりますが、複合代入は暗黙キャストが入るため通ります。
short s = 1;
// s = s + 1; // NG:s + 1 が int になり、short へ暗黙変換できない
s += 1; // OK:複合代入が暗黙キャストを行う
Javaこの仕様に頼りすぎると境界でのバグを招きます。安全策は「最初から int を使う」か、「明示キャストで意図を示す」ことです。さらに、整数のオーバーフローは例外にならず静かに壊れるため、増減が大きい可能性があるなら long を選ぶか、更新後に境界チェックを入れます。
int m = Integer.MAX_VALUE;
m += 1; // -2147483648(循環。要注意)
Java評価順序と短絡でない論理(重要ポイントの深掘り)
&& と || は短絡評価ですが、&= と |= は「必ず右辺を評価」します。副作用のあるメソッド呼び出しを条件に含めると、思わぬ動きになります。
static boolean logTrue() {
System.out.println("右が評価された");
return true;
}
public static void main(String[] args) {
boolean ok = false;
ok = ok && logTrue(); // 左が false → 右は評価されない(短絡)
ok = false; // リセット
ok &= logTrue(); // 非短絡:右を必ず評価する(ログが出る)
}
Java条件分岐には短絡の &&/|| を使い、&=/|= は「右を必ず評価したい理由があるとき」だけに限定すると安全です。
文字列と不変オブジェクトでの複合代入
String は不変(immutable)なので、+= は「新しい文字列を生成して再代入」します。短い連結なら可読性のために許容されますが、ループで多用すると大量のオブジェクトを作ってしまい非効率です。編集が多い場合は StringBuilder を使ってから最後に toString() へ変換するのが定石です。
String title = "Java";
title += " Basics"; // 新しい String へ置き換え
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100; i++) {
sb.append("item").append(i).append('\n');
}
String result = sb.toString();
JavaBigDecimal や BigInteger のような不変オブジェクトは、+= では更新できません。add や multiply の戻り値を再代入する形にします。
import java.math.BigDecimal;
BigDecimal price = new BigDecimal("1999.50");
price = price.multiply(new BigDecimal("0.9")); // 10% 引き
Java例題で身につける
累積合計と平均
public class SumAvg {
public static void main(String[] args) {
int sum = 0;
int[] nums = {3, 8, 2, 7};
for (int n : nums) {
sum += n; // 累積
}
double avg = sum / (double) nums.length;
System.out.printf("sum=%d avg=%.2f%n", sum, avg);
}
}
Javaペナルティ更新と下限ゼロ
public class Penalty {
public static void main(String[] args) {
int points = 10;
points -= 12; // -2
points = Math.max(points, 0); // 下限ゼロへ正規化
System.out.println(points); // 0
}
}
Java権限フラグの付与・除去・トグル
public class Flags {
public static void main(String[] args) {
int READ = 1, WRITE = 2, EXEC = 4;
int perm = 0;
perm |= READ; // 付与
perm |= WRITE; // 付与
perm &= ~READ; // 除去
perm ^= EXEC; // トグル
System.out.println(perm);
}
}
Javaシフトでビット位置を管理
public class Shift {
public static void main(String[] args) {
int mask = 1;
mask <<= 5; // 32 の位置へ
System.out.println(mask); // 32
}
}
Java設計の指針(重要ポイントのまとめ)
複合代入は「更新の意図」を短く明快に示す強力な表現です。short/byte に対する暗黙キャストの例外仕様に頼りすぎず、型は揃えて安全側で選ぶのが基本です。整数のオーバーフローは沈黙するため、範囲を見積もり long や正規化で守りましょう。論理の複合代入(&=/|=)は非短絡であることを理解し、条件分岐には短絡演算子を使って安全な評価順序を設計します。文字列の += は短い連結に限定し、繰り返し編集は StringBuilder へ。不変オブジェクトはメソッドの戻り値を再代入する形で扱う——この流儀を徹底すれば、更新処理のバグは大幅に減ります。
