8.

Java 演算子完全リファレンス

編集
この記事の要点
  • 算術演算子: + - * / %。整数同士の / は切り捨て、% は剰余
  • 比較 / 論理: == != < > <= >= / && || !オブジェクトは == でなく equals() で内容比較
  • ビット演算: & | ^ ~ << >> >>>>>> は符号なし右シフト
  • 三項演算子 ?: + instanceof。Java 14+ で instanceof Pattern Matching
  • 優先順位は覚えるより括弧で明示。バグの 9 割は優先順位の勘違い

算術演算子

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 += 3x = x + 3
-=x -= 3x = x - 3
*=x *= 3x = x * 3
/=x /= 3x = x / 3
%=x %= 3x = x % 3
&=x &= 3x = x & 3
|=x |= 3x = x | 3
^=x ^= 3x = x ^ 3
<<=x <<= 3x = x << 3
>>=x >>= 3x = 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< > <= >= instanceofa < 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) を使う。

編集
Post Share
子ページ
  1. 単項演算子
  2. 算術演算子
  3. 代入演算子
  4. 比較演算子
  5. 論理演算子
同階層のページ
  1. 基本的なルール
  2. データ型
  3. 変数
  4. 定数
  5. 配列
  6. コレクション(List,Set,Queue)
  7. Map(連想配列)
  8. 演算子
  9. 条件分岐
  10. 繰り返し制御文
  11. クラス
  12. メソッド
  13. インスタンス化
  14. コンストラクタ
  15. staticキーワード
  16. オーバーロード
  17. 継承
  18. オーバーライド
  19. this
  20. super
  21. パッケージ
  22. アクセス修飾子
  23. 抽象クラス・メソッド
  24. インターフェース
  25. カプセル化
  26. データベース接続
  27. セッション
  28. ファイル入出力
  29. ラムダ式

最近更新/作成されたページ