Java 入門

Java 演算子

演算子(Operators)は、あらゆるプログラミング言語の屋台骨(スケルトン)であり、計算の実行、データの比較、およびプログラムフローの制御を可能にします。Javaにおいて、演算子は1つ、2つ、または3つのオペランド(変数または値)に対して特定の操作を実行するための特殊な記号です。演算子をしっかりとマスターすることは、効率的なJavaコードを記述するための重要な前提条件です。

本章では、算術演算子、関係演算子、および論理演算子について包括的に解説し、プログラム内でのデータ処理や意思決定に不可欠なツールを提供します。

1. 算術演算子

算術演算子は数学的な計算を行うために使用されます。Javaは、2つのオペランドを必要とする「二項算術演算子」と、1つのオペランドのみで動作する「単項演算子」を提供しています。

1.1 二項算術演算子

これらの演算子は2つのオペランドを使用して計算を行います。

演算子名称説明結果
+加算 (Addition)2つのオペランドを足す。5 + 38
-減算 (Subtraction)最初のオペランドから2番目のオペランドを引く。5 - 32
*乗算 (Multiplication)2つのオペランドを掛ける。5 * 315
/除算 (Division)最初のオペランドを2番目のオペランドで割る。15 / 35
%剰余 (Modulus)除算を行った後の余りを返す。16 % 31

コード例:

public class ArithmeticExample {
    public static void main(String[] args) {
        int a = 10;
        int 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
    }
}

解析: 上記のコードは、整数のオペランドを用いた二項算術演算を示しています。特に注意すべき点として、両方のオペランドが整数(int)の場合、除算演算子 /整数除算を実行し、小数部分は切り捨てられます。

1.2 単項算術演算子

これらの演算子は、単一のオペランドに対してのみ操作を実行します。

演算子名称説明結果
+単項プラス (Unary plus)short, byte, charをintに昇格させる。int以上の型には影響しない。+55
-単項マイナス (Unary minus)式の符号を反転させる。-5-5
++インクリメント (Increment)オペランドの値を1増やす。前置 (++a) または後置 (a++) として使用可能。a++ または ++aaがa+1になる
--デクリメント (Decrement)オペランドの値を1減らす。前置 (--a) または後置 (a--) として使用可能。a-- または --aaがa-1になる

コード例:

public class UnaryExample {
    public static void main(String[] args) {
        int a = 5;
        
        System.out.println("a の初期値: " + a);             // 出力: 5
        System.out.println("単項プラス: " + (+a));          // 出力: 5 (変化なし)
        System.out.println("単項マイナス: " + (-a));          // 出力: -5
        System.out.println("後置インクリメント (Post-increment): " + (a++)); // 出力: 5 (現在のaの値を使用した後、aを1増やす)
        System.out.println("後置インクリメント後の a の値: " + a);        // 出力: 6
        System.out.println("前置デクリメント (Pre-decrement): " + (--a));  // 出力: 5 (aを1減らした後、その新しい値を使用する)
    }
}

解析: インクリメント (++) とデクリメント (--) 演算子の挙動は、それらが前置か後置かによって異なります。

  • 前置 (Prefix)(例:++a): 変数 a の値がまず増加し、その後に式の計算に使用されます。
  • 後置 (Postfix)(例:a++): 変数 a の現在の値が式の計算に使用された後、自身の値が増加します。

1.3 複合代入演算子

Javaは、算術演算と代入操作を一つにまとめた「複合代入演算子」も提供しており、コードをより簡潔に記述できます。

演算子等価な式
+=a += ba = a + b
-=a -= ba = a - b
*=a *= ba = a * b
/=a /= ba = a / b
%=a %= ba = a % b

コード例:

public class CompoundAssignmentExample {
    public static void main(String[] args) {
        int a = 10;
        
        a += 5; // a = a + 5 と同じ
        System.out.println("a += 5: " + a); // 出力: 15
        
        a -= 3; // a = a - 3 と同じ
        System.out.println("a -= 3: " + a); // 出力: 12
        
        a *= 2; // a = a * 2 と同じ
        System.out.println("a *= 2: " + a); // 出力: 24
        
        a /= 4; // a = a / 4 と同じ
        System.out.println("a /= 4: " + a); // 出力: 6
        
        a %= 2; // a = a % 2 と同じ
        System.out.println("a %= 2: " + a); // 出力: 0
    }
}

2. 関係演算子

関係演算子は2つのオペランドを比較するために使用されます。関係演算の結果は常に boolean 値(true または false)となります。

演算子名称説明例 (a=5, b=10)結果
==等しい両方のオペランドが等しければ true、そうでなければ false。a == bfalse
!=等しくない両方のオペランドが等しくなければ true、そうでなければ false。a != btrue
>より大きい最初のオペランドが2番目より大きければ true。a > bfalse
<より小さい最初のオペランドが2番目より小さければ true。a < btrue
>=以上最初のオペランドが2番目以上であれば true。a >= bfalse
<=以下最初のオペランドが2番目以下であれば true。a <= btrue

コード例:

public class RelationalExample {
    public static void main(String[] args) {
        int a = 5;
        int b = 10;
        
        System.out.println("a == b: " + (a == b)); // 出力: false
        System.out.println("a != b: " + (a != b)); // 出力: true
        System.out.println("a > b: " + (a > b));   // 出力: false
        System.out.println("a < b: " + (a < b));   // 出力: true
        System.out.println("a >= b: " + (a >= b)); // 出力: false
        System.out.println("a <= b: " + (a <= b)); // 出力: true
        
        boolean isEqual = (a == 5);
        System.out.println("isEqual (aは5と等しいか): " + isEqual); // 出力: true
    }
}

解析: 関係演算子は、条件分岐ステートメント(次モジュールで解説)において、特定の条件に基づいてプログラムの実行フローを制御するために極めて頻繁に使用されます。a == 5 のような比較が示すように、変数同士だけでなく、変数と具体的なリテラル(固定値)を比較することも可能です。

3. 論理演算子

論理演算子は、2つ以上のブール式を組み合わせるために使用されます。論理演算の結果も常に boolean 値(true または false)となります。

演算子名称説明例 (a=true, b=false)結果
&&論理積 (AND)両方のオペランドが true の場合のみ true を返す。ショートサーキット特性を持つ。a && bfalse
||論理和 (OR)少なくとも一方のオペランドが true であれば true を返す。ショートサーキット特性を持つ。a || btrue
!論理否定 (NOT)オペランドの論理値を反転させる。真は偽に、偽は真になる。!afalse
&ビット単位AND / 論理AND&&に似ているが、ショートサーキットせず常に両辺を評価する。a & bfalse
|ビット単位OR / 論理OR||に似ているが、ショートサーキットせず常に両辺を評価する。a | btrue
^排他的論理和 (XOR)一方が真で、もう一方が偽の場合のみ true を返す。a ^ btrue

コード例:

public class LogicalExample {
    public static void main(String[] args) {
        boolean a = true;
        boolean b = false;
        
        System.out.println("a && b: " + (a && b)); // 出力: false
        System.out.println("a || b: " + (a || b)); // 出力: true
        System.out.println("!a: " + (!a));         // 出力: false
        
        System.out.println("a & b: " + (a & b));   // 出力: false
        System.out.println("a | b: " + (a | b));   // 出力: true
        System.out.println("a ^ b: " + (a ^ b));   // 出力: true
    }
}

詳細解説:

  • ショートサーキット評価 (Short-circuiting): &&|| 演算子はショートサーキット挙動を持ちます。これは、左辺のオペランドを評価しただけで式全体の結果が確定する場合、Javaは右辺のオペランドを評価(実行)しないことを意味します。
    • 例えば a && b において、a が既に false であれば、式全体の結果は false に確定するため、b は評価されません。
    • 同様に a || b において、a が既に true であれば、結果は true に確定するため、b はスキップされます。
  • ビット単位 vs 論理: &| は元来ビット演算子ですが、ブール値に対しても使用可能です。&&|| との最大の違いはショートサーキット特性がないことであり、左辺の結果に関わらず右辺の式が必ず実行されます。日常的な論理判断では、通常 &&|| の使用が強く推奨されます。
  • 排他的論理和 (XOR): ^ は、両辺の状態が「異なる」(一方が真で他方が偽)場合にのみ true を返します。両方とも真、あるいは両方とも偽の場合は false を返します。

3.1 演算子の組み合わせ

複数の演算子を組み合わせて、より複雑な式を作成できます。括弧 () を使用して演算の優先順位を制御できます。

コード例:

public class CombinedOperators {
    public static void main(String[] args) {
        int age = 25;
        boolean isStudent = true;
        
        // 割引対象かどうかをチェック(18歳未満 または 学生である)
        boolean eligibleForDiscount = (age < 18) || isStudent;
        System.out.println("割引資格の有無: " + eligibleForDiscount); // 出力: true
        
        // 成人 かつ 学生ではない かどうかをチェック
        boolean isAdultAndNotStudent = (age >= 18) && !isStudent;
        System.out.println("成人かつ非学生: " + isAdultAndNotStudent); // 出力: false
    }
}

4. 演算子の優先順位

演算子の優先順位は、複雑な式の中で各演算子が実行される順番を決定します。優先順位の高い演算子は、低い演算子よりも先に評価されます。

以下は、解説した演算子の優先順位(高い順)です:

優先順位演算子
1++, -- (後置 Postfix)
2++, -- (前置 Prefix), + (単項正), - (単項負), !
3*, /, %
4+, -
5==, !=, >, <, >=, <=
6&
7^
8|
9&&
10||
11=, +=, -=, *=, /=, %= (代入系)

コード例:

public class OperatorPrecedence {
    public static void main(String[] args) {
        int a = 5;
        int b = 10;
        int c = 2;
        
        int result = a + b * c; // 乗算は加算より優先順位が高い
        System.out.println("a + b * c: " + result); // 出力: 25 (5 + (10 * 2) と同じ)
        
        int result2 = (a + b) * c; // 括弧 () は最高優先順位。演算順序を強制的に変える
        System.out.println("(a + b) * c: " + result2); // 出力: 30 ((5 + 10) * 2 と同じ)
        
        boolean boolResult = a > b || b < c && a == 5;
        System.out.println("括弧なしの論理組み合わせ: " + boolResult); // 出力: false
        /* 実行順序の解析:
           1. まず && の両辺を評価: b < c は false (10 < 2)
           2. 関係演算 a == 5 は true (5 == 5)
           3. false && true の結果は false
           4. 次に || の両辺を評価: a > b は false (5 > 10)
           5. 最終結果: false || false は false
        */
    }
}

解析: 演算子の優先順位を覚えておくことは非常に重要です。これにより、プログラムが予期せぬ結果を出すのを防ぐことができます。順序が不明確な場合は、積極的に括弧 () を使用しましょう。これは実行順序を確実に保証するだけでなく、コードの可読性(人間にとっての読みやすさ)を大幅に向上させます。