タイトル: 演算子
SEOタイトル: Java 演算子完全リファレンス
| この記事の要点 |
|
算術演算子
int a = 10, b = 3;
System.out.println(a + b); // 13
System.out.println(a - b); // 7
System.out.println(a * b); // 30
System.out.println(a / b); // 3 ★ 整数除算は切り捨て
System.out.println(a % b); // 1 ★ 剰余
// 浮動小数で計算したい場合は片方を double に
System.out.println((double) a / b); // 3.3333...
System.out.println(a / (double) b); // 3.3333...
// 文字列連結も + で
String s = "x = " + a; // "x = 10"
// オーバーフロー(int は約 21 億まで)
int max = Integer.MAX_VALUE; // 2_147_483_647
System.out.println(max + 1); // -2147483648 ★ ラップアラウンド
// 安全な演算 (Java 8+)
int safe = Math.addExact(max, 1); // ArithmeticException
代入演算子
| 演算子 | 例 | 等価な式 |
|---|---|---|
= | x = 5 | - |
+= | x += 3 | x = x + 3 |
-= | x -= 3 | x = x - 3 |
*= | x *= 3 | x = x * 3 |
/= | x /= 3 | x = x / 3 |
%= | x %= 3 | x = x % 3 |
&= | x &= 3 | x = x & 3 |
|= | x |= 3 | x = x | 3 |
^= | x ^= 3 | x = x ^ 3 |
<<= | x <<= 3 | x = x << 3 |
>>= | x >>= 3 | x = x >> 3 |
比較演算子と参照比較の罠
// プリミティブの比較: 値の比較
int a = 1, b = 1;
System.out.println(a == b); // true
// オブジェクトの比較: ★ 参照比較になる!
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2); // false ★ 別インスタンス
System.out.println(s1.equals(s2)); // true ★ 内容比較
// String リテラルは「文字列プール」で同一インスタンス化される
String s3 = "hello";
String s4 = "hello";
System.out.println(s3 == s4); // true ★(同じプールを参照)
// Integer の罠
Integer i1 = 127, i2 = 127;
Integer i3 = 128, i4 = 128;
System.out.println(i1 == i2); // true ★ -128〜127 はキャッシュ
System.out.println(i3 == i4); // false ★ 128 以上は別インスタンス
System.out.println(i3.equals(i4));// true
// ★ ルール: オブジェクト同等性は必ず equals()
論理演算子
boolean a = true, b = false;
// 短絡評価 (Short-Circuit)
System.out.println(a && b); // false。a が false なら b 評価しない
System.out.println(a || b); // true。 a が true なら b 評価しない
System.out.println(!a); // false
// 非短絡(左右両方評価)
System.out.println(a & b); // false
System.out.println(a | b); // true
// null セーフ
String s = null;
if (s != null && s.length() > 0) { // ★ && が短絡なので NPE 起きない
// ...
}
// ❌ 順序を逆にすると NPE
if (s.length() > 0 && s != null) { // NullPointerException
// ...
}
ビット演算子
int a = 0b1100; // 12
int b = 0b1010; // 10
System.out.println(Integer.toBinaryString(a & b)); // 1000 (AND)
System.out.println(Integer.toBinaryString(a | b)); // 1110 (OR)
System.out.println(Integer.toBinaryString(a ^ b)); // 0110 (XOR)
System.out.println(Integer.toBinaryString(~a)); // ...11110011 (NOT, 補数)
// シフト演算
int n = 8; // 1000
System.out.println(n << 2); // 32 (100000) ← 左シフト = ×2^2
System.out.println(n >> 1); // 4 (100) ← 右シフト = ÷2
// >>> 符号なし右シフト(Java 独自)
int neg = -1; // 0xFFFFFFFF
System.out.println(neg >> 1); // -1(符号維持)
System.out.println(neg >>> 1); // 2147483647(先頭に 0 を詰める)
// 用途: ビットフラグ
int FLAG_READ = 1; // 001
int FLAG_WRITE = 2; // 010
int FLAG_EXEC = 4; // 100
int perms = FLAG_READ | FLAG_WRITE; // 011
if ((perms & FLAG_WRITE) != 0) {
System.out.println("write permission");
}
インクリメント / デクリメント
int a = 5;
// 前置: 先にインクリメント
int b = ++a; // a=6, b=6
// 後置: 評価後にインクリメント
int c = a++; // c=6, a=7
// ループでよく使う
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
// ★ 同じ式で複数回使うのは未定義動作の元
int x = 5;
int y = x++ + ++x; // 言語仕様上は確定するが可読性が悪い → 避ける
三項演算子
int age = 20;
String category = (age >= 18) ? "adult" : "minor";
// ネストはなるべく避ける(可読性低下)
String grade = score >= 80 ? "A"
: score >= 60 ? "B"
: score >= 40 ? "C"
: "F";
// null チェック
String name = (user != null) ? user.getName() : "anonymous";
// Java 9+ Optional のほうが読みやすい場合も
String name2 = Optional.ofNullable(user)
.map(User::getName)
.orElse("anonymous");
instanceof と Pattern Matching
Object obj = "hello";
// 旧来の instanceof
if (obj instanceof String) {
String s = (String) obj; // ★ キャストが必要
System.out.println(s.length());
}
// Java 16+ Pattern Matching for instanceof
if (obj instanceof String s) { // ★ キャスト不要、変数 s で使える
System.out.println(s.length());
}
// Java 21 Pattern Matching for switch
String describe(Object o) {
return switch (o) {
case Integer i -> "int: " + i;
case String s -> "str: " + s;
case null -> "null";
default -> "other";
};
}
演算子の優先順位 (一部)
| 順位 | 演算子 | 例 |
|---|---|---|
| 1 (高) | 後置 ++ -- , . , () , [] | a++ |
| 2 | 前置 ++ -- + - ! ~ , キャスト | ++a , (int) x |
| 3 | * / % | a * b |
| 4 | + - | a + b |
| 5 | << >> >>> | a << 2 |
| 6 | < > <= >= instanceof | a < b |
| 7 | == != | a == b |
| 8 | & | a & b |
| 9 | ^ | a ^ b |
| 10 | | | a | b |
| 11 | && | a && b |
| 12 | || | a || b |
| 13 | ?: 三項 | a ? b : c |
| 14 (低) | = += -= ... 代入 | a = b |
原則: 優先順位を覚えるより括弧で明示。if ((a & FLAG) != 0) のように。
FAQ
Q: String の比較は == でも動く時があるが?
A: コンパイル時定数(リテラル)は文字列プールに格納され同一参照になります。ただし依存すべきではなく、必ず equals() を使ってください。
Q: i == i + 1 は常に false?
A: int の場合は常に false。ただし double では巨大な値で 1.0e20 == 1.0e20 + 1 が true になります(精度不足)。
Q: NaN == NaN は?
A: false。NaN は自分自身とも等しくありません。判定は Double.isNaN(x) を使う。