読み込み中...

初心者がJavaで覚えるべき二項演算子の13選

Java言語の二項演算子を解説するイラスト Java
この記事は約25分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

Javaの二項演算子は、2つの値を組み合わせて計算、比較、条件判定、ビット単位の処理を行うための記号です。初心者が最初につまずきやすいのは、+-のような見た目が分かりやすい演算と、&&||<<のように評価順や型変換まで関係する演算を同じ感覚で読んでしまう点にあります。そのため、二項演算子の使い方は、記号を暗記するよりも「左辺と右辺に何を置き、結果がどの型になるか」で整理すると理解しやすくなります。

公式ドキュメントによれば、Javaの演算子には優先順位があり、同じ式の中では優先順位の高い演算から評価されますが、これは押さえたい点です。詳しい優先順位はOracle Java Tutorials Operatorsで確認できます。仕様上の評価順や式の意味はJava Language Specification Chapter 15にまとまっているのが基本です。

関連する型や構文を並行して確認したい場合は、Java List型の基礎Javaアノテーションの考え方Javaでの条件判定Javaエスケープ処理Javaのオーバーライドも合わせて読むと、サンプルコード内の文脈を追いやすくなります。

動作確認環境
  • Java 21
  • OpenJDK 21 / 標準ライブラリのみ
📖 この記事で学べること
  • Javaの二項演算子が受け取る2つの値と戻り値の考え方
  • 算術、比較、論理、ビット演算の使い方と読み方
  • 初心者が間違えやすい0除算、浮動小数点数、優先順位の注意点
  • サンプルコードを使った条件判定、フラグ管理、ストリーム処理の組み立て方
  • 演算処理をメソッドやラムダ式でカスタマイズする考え方

Javaの二項演算子とは

a + bのように、左側の値と右側の値を受け取って結果を返す記号が二項演算子です。Javaでは、値そのものをintdoublebooleanStringなどの型として扱うため、同じ記号でも組み合わせる型によって意味が変わります。たとえば+は数値なら加算ですが、片方がStringなら文字列結合になります。

これを理解するには、演算子だけでなくオペランドの型を見る必要があるのがポイントです。そのため、初心者は「記号の名前」だけでなく「左辺、演算子、右辺、結果の型」を並べて読むのが現実的です。演算の結果は変数へ代入したり、if文の条件に使ったり、returnでメソッドの戻り値にしたりできます。

二項演算子の基本概念

Javaでよく使う二項演算子は、算術演算子、比較演算子、論理演算子、ビット演算子、代入を伴う複合代入演算子に分けると整理しやすくなります。算術演算子は+-*/%で数値の演算を行い、比較演算子は==!=<><=>=trueまたはfalseを返するのが一般的です。

一方、論理演算子の&&||boolean同士を組み合わせる場面で使います。ビット演算子の&|^<<>>>>>は整数をビット列として扱うため、フラグ管理や低レイヤ寄りの処理で見かけます。+=-=*=/=%=&=|=のような複合代入は、演算と代入を短く書く構文です。

分類主な演算子戻り値使いどころ注意点
算術+ - * / %数値四則演算、余りの計算int同士の/は整数除算
比較== != < > <= >=boolean条件分岐、ループ判定参照型の同値判定はequalsも検討
論理&& ||boolean複数条件の結合短絡評価により右辺が評価されない場合あり
ビット& | ^整数またはbooleanフラグ管理、ビット単位の処理&&||と混同しない
シフト<< >> >>>整数2の累乗倍、符号付きビット移動負数では符号ビットの扱いに注意
複合代入+= -= |=代入後の値累積、設定追加暗黙の型変換が関係する場合あり

この分類を押さえると、サンプルコードを読むときに式の目的を先に推測できます。たとえばscore >= 80 && passedなら、比較で得たbooleanと別のbooleanを論理積で結合している式だと分かります。演算子の優先順位が不安な場合は、()で評価したいまとまりを明示すると読み間違いを減らせますし、ここがポイントです。

💡 Tips: 二項演算子の式は、左辺、演算子、右辺、結果の型の順で読むと整理しやすくなるのが現実的です。特に初心者は、==が代入ではなく比較である点を早めに区別すると、条件分岐の読み取りが安定します。

二項演算子の使い方

二項演算子の使い方は、変数に値を入れ、式で演算し、結果を別の変数や条件式に渡す流れで確認できます。Javaではmainメソッドに小さなサンプルコードを書けば、クラス単位で挙動を追いやすくなると整理できます。ただし、コードの出力例は環境で実行した事実ではなく、記述から導ける期待される出力として扱いるのが目安です。

サンプルコード1:算術演算子を使う

算術演算子は、数値を扱うJavaコードの入口になります。int同士の足し算、引き算、掛け算、割り算、剰余を同じ場所で確認すると、/%の違いも見えやすくなります。

public class ArithmeticOperatorExample {
    public static void main(String[] args) {
        int num1 = 10;
        int num2 = 20;

        // 足し算
        int sum = num1 + num2;  // 30が格納される

        // 引き算
        int diff = num1 - num2;  // -10が格納される

        // 掛け算
        int product = num1 * num2;  // 200が格納される

        // 割り算
        int quotient = num1 / 2;  // 5が格納される

        // 剰余(余り)
        int remainder = num1 % 3;  // 1が格納される
    }
}

結果: 期待される変数の値は、sum30diff-10product200quotient5remainder1です。

このサンプルコードでは、num1num2を使って基本的な演算をまとめています。そのため、初心者はquotientが小数ではなく整数になる点に注意すると、後の0除算や型変換の説明へつながります。

サンプルコード2:比較演算子を用いた数値の比較

比較演算子は、数値の大小関係や等しさをbooleanで返すると理解できます。条件分岐のifや繰り返しのwhileでは、この結果が処理を分ける基準になります。

public class ComparisonOperatorExample {
    public static void main(String[] args) {
        int a = 5;
        int b = 10;

        // 等しいかどうか
        boolean isEqual = (a == b);  // falseが格納される

        // 等しくないかどうか
        boolean isNotEqual = (a != b);  // trueが格納される

        // より大きいかどうか
        boolean isGreater = (a > b);  // falseが格納される

        // より小さいかどうか
        boolean isSmaller = (a < b);  // trueが格納される

        // より大きいか等しいかどうか
        boolean isGreaterOrEqual = (a >= b);  // falseが格納される

        // より小さいか等しいかどうか
        boolean isSmallerOrEqual = (a <= b);  // trueが格納される
    }
}

結果: 期待される値は、isEqualfalseisNotEqualtrueisGreaterfalseisSmallertrueisGreaterOrEqualfalseisSmallerOrEqualtrueです。

これらの式は、左辺と右辺を比較して真偽値を作ります。一方、=は代入、==は比較なので、条件式で=を書いてしまうミスはJava初心者に多い注意点です。

サンプルコード3:論理演算子を用いた条件判定

論理演算子は、複数の条件をまとめるときに使います。&&は両方がtrueのときだけtrueになり、||はどちらか一方がtrueならtrueになると覚えるとよいでしょう。

public class LogicalOperatorExample {
    public static void main(String[] args) {
        boolean condition1 = true;
        boolean condition2 = false;

        // 論理積(両方の条件がtrueであればtrueを返す)
        boolean andResult = condition1 && condition2;  // falseが格納される

        // 論理和(どちらか一方がtrueであればtrueを返す)
        boolean orResult = condition1 || condition2;  // trueが格納される

        // 論理否定(条件がfalseであればtrueを返す、逆も然り)
        boolean notResult = !condition1;  // falseが格納される
    }
}

結果: 期待される値は、andResultfalseorResulttruenotResultfalseです。

この例ではcondition1truecondition2falseなので、論理積と論理和の違いがはっきり出ます。ただし、!は単項演算子であり、二項演算子ではないため、条件の反転に使う補助的な記号として分けて覚えるとよいです。

サンプルコード4:ビット演算を試す

ビット演算は、整数を2進数の並びとして見たときに、各桁を組み合わせる演算です。&は両方のビットが1の位置だけを残し、|はどちらかが1なら1にし、^は片方だけが1の位置を1にします。

public class BitwiseOperatorExample {
    public static void main(String[] args) {
        int num1 = 5;  // 二進数で 0101
        int num2 = 3;  // 二進数で 0011

        // ビット積
        int andBitwise = num1 & num2;  // 1が格納される(二進数で 0001)

        // ビット和
        int orBitwise = num1 | num2;  // 7が格納される(二進数で 0111)

        // ビット否定
        int notBitwise = ~num1;  // -6が格納される(二進数で 11111111111111111111111111111010)

        // 排他的論理和
        int xorBitwise = num1 ^ num2;  // 6が格納される(二進数で 0110)
    }
}

結果: 期待される値は、andBitwise1orBitwise7notBitwise-6xorBitwise6です。

このサンプルコードには~も含まれていますが、~num1は1つの値だけを反転する単項演算子です。そのため、二項演算子として見るべき中心はnum1 & num2num1 | num2num1 ^ num2になります。

二項演算子の応用例

基礎の演算が読めるようになると、メソッド化、条件分岐、フラグ管理、シフト処理へ応用できます。Javaの二項演算子は単独で完結する記号ではなく、classstaticメソッド、ifSystem.out.printlnなどと組み合わせて処理の意味を作りますし、これが一つの目安です。

サンプルコード5:算術演算子を使った簡易計算機

四則演算をメソッドに分けると、演算子の役割と処理の名前が対応します。除算だけは分母が0になる可能性があるため、Double.NaNを返す分岐を入れています。

public class SimpleCalculator {
    // 加算
    public static int add(int a, int b) {
        return a + b;
    }

    // 減算
    public static int subtract(int a, int b) {
        return a - b;
    }

    // 乗算
    public static int multiply(int a, int b) {
        return a * b;
    }

    // 除算
    public static double divide(int a, int b) {
        if (b == 0) {
            return Double.NaN; // 0で除算する場合はNaN(Not a Number)を返す
        }
        return (double) a / b;
    }

    public static void main(String[] args) {
        System.out.println(add(5, 3));  // 出力は8
        System.out.println(subtract(5, 3));  // 出力は2
        System.out.println(multiply(5, 3));  // 出力は15
        System.out.println(divide(5, 3));  // 出力は1.6666666666666667
    }
}

結果: 期待される出力は、82151.6666666666666667の順です。

このJavaコードでは、addsubtractmultiplydivideがそれぞれ演算の役割を持ちます。特に(double) a / bのようにキャストを入れると、整数除算ではなく小数を含む結果を扱えます。

サンプルコード6:複数の条件を組み合わせて判定する

複数条件の判定では、比較演算子で作ったbooleanと、既存のboolean変数を論理演算子で結合すると考えられます。業務ロジックでは点数、権限、在庫、有効期限などの条件をまとめて判定する形がよく見られます。

public class MultiConditionsExample {
    public static void main(String[] args) {
        int score = 85;
        boolean isHandsome = true;

        if (score > 80 && isHandsome) {
            System.out.println("素晴らしい!");
        } else if (score > 80 || isHandsome) {
            System.out.println("なかなか良い!");
        } else {
            System.out.println("がんばりましょう!");
        }
    }
}

結果: 期待される出力は素晴らしい!です。

この例ではscore > 80trueになり、isHandsometrueです。そのため、最初のif条件であるscore > 80 && isHandsomeが成立します。

⚠️ 注意: 変数名や表示文は学習用の例として読み替え可能です。実際のアプリケーションでは、判定対象が利用者属性や評価に関わる場合、説明責任や公平性に配慮した命名と条件設計が求められます。

サンプルコード7:ビットフラグを活用した設定の管理

ビットフラグは、複数のオンオフ設定を1つの整数に詰め込む方法です。NOTIFYDARK_MODEVOICE_RECOGのように異なるビット位置を割り当てると、|=で設定を追加し、&で含まれているかを判定できると言えるでしょう。

public class BitFlagExample {
    // 各設定項目に対応するビットフラグ
    public static final int NOTIFY = 1;  // 0001
    public static final int DARK_MODE = 2;  // 0010
    public static final int VOICE_RECOG = 4;  // 0100

    public static void main(String[] args) {
        int settings = 0;  // 設定を初期化

        // 通知とダークモードを有効にする
        settings |= NOTIFY;
        settings |= DARK_MODE;

        // 設定をチェックする
        if ((settings & NOTIFY) == NOTIFY) {
            System.out.println("通知が有効です。");
        }
        if ((settings & DARK_MODE) == DARK_MODE) {
            System.out.println("ダークモードが有効です。");
        }
        if ((settings & VOICE_RECOG) == VOICE_RECOG) {
            System.out.println("音声認識が有効です。");
        } else {
            System.out.println("音声認識は無効です。");
        }
    }
}

結果: 期待される出力は、通知が有効です。ダークモードが有効です。音声認識は無効です。です。

このJavaコードでは、settingsの各ビットが設定項目を表します。ビット演算によるカスタマイズはメモリ効率の面で扱いやすい場合がありますが、項目が増えると可読性が落ちるため、EnumSetなどの代替も検討できます。

サンプルコード8:シフト演算を使った高速計算テクニック

シフト演算は、整数のビット列を左右に移動する演算です。左シフトの<<は2の累乗倍と対応するため、1 << 3は8になるのが基本です。

public class ShiftExample {
    public static void main(String[] args) {
        int num = 1;

        // 2の3乗を計算(左シフトで高速計算)
        num = num << 3;

        System.out.println("2の3乗は" + num + "です。");
    }
}

結果: 期待される出力は2の3乗は8です。です。

ただし、現代のJITコンパイラは単純な乗算を最適化できるため、読みやすさを犠牲にしてまでシフト演算へ置き換える必要はありません。そのため、<<は高速化の記号として暗記するより、ビット位置を扱う演算として理解するほうが実用的です。

注意点と対処法

二項演算子の注意点は、見た目の短さに対して結果が型、評価順、例外、丸め誤差に左右されるところです。Javaではintの0除算でArithmeticExceptionが発生し、doubleの比較では2進表現の都合で期待した等価判定にならない場合があります。

そのため、初心者は「計算式が短いから安全」と考えず、分母、型、比較方法を確認する習慣を持つとよいです。特に押さえたいのは、/%==&&の周辺で発生しやすい不具合です。

サンプルコード9:割り算のときの0除算を避ける

整数の割り算では、分母が0になると処理が例外で中断します。分母が外部入力、設定値、計算途中の値に由来する場合は、割り算の前に条件判定を置くのが基本になるのが目安です。

public class ZeroDivisionExample {
    public static void main(String[] args) {
        int numerator = 10;
        int denominator = 0;

        // 0除算を避ける
        if (denominator != 0) {
            int result = numerator / denominator;
            System.out.println("結果は " + result + " です。");
        } else {
            System.out.println("0で割ることはできません。");
        }
    }
}

結果: 期待される出力は0で割ることはできません。です。

この対処法では、denominator != 0で安全に割れるかを先に判定しています。一方、doubleの0除算ではInfinityNaNになるケースがあるため、整数と浮動小数点数の違いも合わせて確認すると理解が深まります。

サンプルコード10:浮動小数点数の比較における注意

浮動小数点数は、多くの小数を2進数で正確に表せません。そのため、0.1 + 0.20.3==で直接比較すると、数学上の期待と異なる結果になる場合があるのがポイントです。

public class FloatComparisonExample {
    public static void main(String[] args) {
        double a = 0.1 + 0.2;
        double b = 0.3;
        final double EPSILON = 1E-14;  // 許容誤差

        // 許容誤差を持たせて比較
        if (Math.abs(a - b) < EPSILON) {
            System.out.println("ほぼ等しい");
        } else {
            System.out.println("等しくない");
        }
    }
}

結果: 期待される出力はほぼ等しいです。

このサンプルコードでは、Math.abs(a - b)で差の絶対値を求め、EPSILONより小さいかを判定します。ただし、許容誤差の値は扱う金額、測定値、座標などの性質によって変わるため、用途に合わせた設計が必要です。

⚠️ 注意: 金額計算ではdoubleの丸め誤差が問題になりやすいため、BigDecimalの利用を検討します。二項演算子の使い方だけでなく、型の選択も結果の正確さに関わりますが、覚えておくと役立つでしょう。

カスタマイズ方法

JavaはC++のような演算子オーバーロードを提供していません。そのため、独自の演算を作りたい場合は、メソッド、インターフェース、ラムダ式、ストリームAPIを使って処理を表現します。

こうしたカスタマイズでは、記号そのものを増やすのではなく、addcomparereduceのように名前付きの処理へ置き換えます。サンプルコードを追うと、二項演算子の役割をメソッド境界の中に閉じ込める考え方が分かりますし、ここを基本と考えるとよいでしょう。

サンプルコード11:カスタム演算子を定義する

独自型の加算を表したい場合、Javaでは+を再定義できないため、メソッドで同等の意味を持たせます。ベクトル同士の加算なら、x成分とy成分をそれぞれ足した新しいVectorを返す形になります。

public class Vector {
    public int x, y;

    public Vector(int x, int y) {
        this.x = x;
        this.y = y;
    }

    // ベクトル加算のカスタムメソッド
    public Vector add(Vector another) {
        return new Vector(this.x + another.x, this.y + another.y);
    }

    public static void main(String[] args) {
        Vector v1 = new Vector(2, 3);
        Vector v2 = new Vector(4, 5);
        Vector result = v1.add(v2);

        System.out.println("Result: (" + result.x + ", " + result.y + ")");
    }
}

結果: 期待される出力はResult: (6, 8)です。

このJavaコードでは、v1.add(v2)がベクトル加算の役割を持ちます。ただし、公開フィールドのpublic int x, yは学習用として短く書かれているため、実用コードではprivate finalやアクセサを使う設計も候補になります。

サンプルコード12:ラムダ式との連携

ラムダ式を使うと、比較や計算のルールを値のように渡せますし、ここがポイントです。Comparator<Integer>は2つのIntegerを受け取り、大小関係をintで返すため、二項演算子を含む比較ロジックと相性があります。

import java.util.Comparator;

public class LambdaExample {
    public static void main(String[] args) {
        Comparator<Integer> comparator = (x, y) -> (x % 2) - (y % 2);

        int result = comparator.compare(3, 4);
        System.out.println("比較結果: " + result);
    }
}

結果: 期待される出力は比較結果: 1です。

この例では3 % 214 % 20なので、差は1になります。元記事の説明にある-1とは符号が逆になるため、式の読み取りでは剰余の結果を順に追う必要があります。

サンプルコード13:ストリームAPIでの演算子の活用

ストリームAPIでは、複数の値を順に畳み込む処理で演算を扱えますが、これは押さえたい点です。IntStream.range(1, 6)1から5までの整数を作り、reduceで合計値にまとめます。

import java.util.stream.IntStream;

public class StreamExample {
    public static void main(String[] args) {
        int sum = IntStream.range(1, 6)  // 1から5までの整数ストリーム
                          .reduce(0, Integer::sum);  // 合計を求める

        System.out.println("合計: " + sum);
    }
}

結果: 期待される出力は合計: 15です。

このサンプルコードでは、Integer::sumが2つの整数を受け取って足す処理として使われます。明示的にa + bを書かなくても、reduceの中では二項演算に相当する処理が繰り返されていると理解できます。

ℹ️ 補足: ストリームAPIのreduceは、初期値と結合処理を組み合わせて値を集約するのが一般的です。合計以外にも最大値、最小値、積、独自集計などへカスタマイズできます。

まとめ

Javaの二項演算子は、2つの値を受け取り、計算結果や真偽値を返す構文です。算術、比較、論理、ビット、シフト、複合代入を分けて読むと、サンプルコード内の式が何をしているか判断しやすくなります。

その理解を実用に近づけるには、演算子の記号だけでなく、型と評価順を合わせて見る必要があるのが現実的です。int同士の割り算、doubleの比較、&&の短絡評価、&&&の違いは、初心者が早い段階で押さえたい注意点です。

カスタマイズの場面では、Javaに演算子オーバーロードがないため、メソッド、ラムダ式、ストリームAPIで処理を表します。Vector.addComparator.compareIntStream.reduceのように名前を付けることで、複雑な演算でも読みやすい形にできます。

二項演算子の使い方を身につけると、条件分岐、計算処理、設定管理、集計処理のコードを読み書きしやすくなると整理できます。サンプルコードを小さく動かす前提で読み、期待される出力と式の関係を照合すると、Javaの演算に対する理解が安定します。

関連記事

著者: Japanシーモア編集部

Japanシーモアは、Web/IoT/APP/SYS 分野のプログラミング情報を体系的に提供するメディアです。本記事は編集部による執筆とAI支援を組み合わせて制作し、公開前に編集部が校正しています。誤りや改善案がございましたらお問い合わせよりご連絡ください。

※本記事は実在のエンジニア複数名で構成される Japanシーモア編集部が、AI支援を活用して作成・校正・公開しています。