Java | 基礎文法:比較演算子

Java Java
スポンサーリンク

比較演算子の全体像

Java の比較演算子は「式の真偽を判定して boolean を返す」ための基本ツールです。代表は ==!=<><=>= で、数値や文字の大小、同値性を判定します。重要なのは「プリミティブ(値そのもの)と参照型(オブジェクト)で意味が違う」こと、そして浮動小数点の比較には誤差や NaN の罠があることです。


基本の比較演算子と整数・char の挙動

整数の比較

整数同士の比較は直感どおりに動きます。結果は boolean です。

int a = 7, b = 3;
System.out.println(a == b);  // false
System.out.println(a != b);  // true
System.out.println(a > b);   // true
System.out.println(a <= b);  // false
Java

「演算の後に比較」する場合は、演算の型(intlong の混在など)が意図通りかを確認しましょう。型が広い方へ自動昇格されます。

char の比較(コードポイント順)

char は UTF-16 のコード単位です。大小比較はコード値順で行われます。

char x = 'A', y = 'a';
System.out.println(x < y); // true('A' のコードが 'a' より小さい)
Java

絵文字などサロゲートペアが必要な文字は char 1 つに収まらないため、大小比較は StringcompareTo やコードポイント API を使う方が安全です。


浮動小数点の比較と NaN/Infinity(重要ポイントの深掘り)

誤差を踏まえた比較

浮動小数点(double/float)は二進小数で誤差が付きやすく、完全一致比較は危険です。許容誤差(イプシロン)を使うのが定石です。

double r = 0.1 + 0.2;             // 0.30000000000000004 など
double eps = 1e-9;
boolean eq = Math.abs(r - 0.3) < eps;
System.out.println(eq); // true(誤差内として同値扱い)
Java

「計算結果を表示だけ丸めたい」場合は printf("%.2f")、「計算自体を厳密にしたい(金額など)」場合は BigDecimal を使います。

NaN と Infinity の比較ルール

double/float には特別値があります。ゼロ割りや未定義計算で発生します。

System.out.println(1.0 / 0.0);    // Infinity
System.out.println(0.0 / 0.0);    // NaN
System.out.println(Double.NaN == Double.NaN); // false(NaN は何とも等しくない)
System.out.println(Double.isNaN(Double.NaN)); // true(判定は専用メソッド)
Java

比較前に Double.isNaN(x)Double.isInfinite(x) でガードし、異常値を明確に扱うのが安全です。


参照型の比較:== と equals の違い(重要ポイントの深掘り)

参照の同一性(==)と内容の同値性(equals)

== は「同じインスタンスか」を比較し、equals は「内容が同じか」を比較します。文字列やコレクションの比較は必ず equals を使うのが原則です。

String a = "hi";
String b = new String("hi");
System.out.println(a == b);      // false(別インスタンス)
System.out.println(a.equals(b)); // true(内容は同じ)
Java

equals をオーバーライドするクラスでは、hashCode も整合させることが契約です。マップやセットでの動作に直結します。

ラッパークラスの罠(Integer など)

Integer などのラッパー型はオブジェクトです。== は参照比較になるため、意図通りの結果にならないことがあります(値キャッシュの影響もある)。

Integer x = 128;
Integer y = 128;
System.out.println(x == y);       // false(参照が違うことが多い)
System.out.println(x.equals(y));  // true(値比較)
Java

プリミティブにアンボックスして比較するか、equals を使うのが安全です。


文字列の順序比較と部分一致

文字列の順序比較(辞書順)

String.compareTo は辞書順で比較します。0 が同値、負が「小さい」、正が「大きい」を意味します。

System.out.println("Apple".compareTo("Banana")); // 負(Apple の方が前)
System.out.println("Hi".compareTo("Hi"));        // 0(同値)
Java

大小比較はロケールの影響を受けない単純なコード値順です。言語学的な順序が必要なら Collator を使います。

部分一致・前方/後方一致

部分一致は contains、前方一致は startsWith、後方一致は endsWith を使います。

String s = "hello.java";
System.out.println(s.contains("java"));    // true
System.out.println(s.startsWith("hello")); // true
System.out.println(s.endsWith(".java"));   // true
Java

大小無視の比較は equalsIgnoreCase。ロケール依存のケースでは toLowerCase(Locale.ROOT) などで正規化してから比較します。


BigDecimal と厳密比較、整数の境界(重要ポイントの深掘り)

BigDecimal は compareTo を使う

金額などの厳密比較は BigDecimalequals はスケール(小数点桁)も比較するため、「1.0」と「1」は等しくありません。値比較には compareTo を使います。

import java.math.BigDecimal;

BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("1");
System.out.println(a.equals(b));        // false(スケールが違う)
System.out.println(a.compareTo(b) == 0);// true(数値として同値)
Java

境界値とオーバーフローの前提チェック

大小比較の前に「範囲に収まるか」を確認しておくと安全です。int の加算は静かにオーバーフローします。大きな値なら long を選び、必要なら境界チェックを入れます。

int max = Integer.MAX_VALUE;
int n = max - 10;
System.out.println(n < max); // true(境界の直前)
Java

null 安全な比較とユーティリティ

null を含む同値判定

Objects.equals(a, b) はどちらかが null でも安全に内容比較できます。手書きの a != null && a.equals(b) を簡潔に置き換えられます。

import java.util.Objects;

String a = null, b = "hi";
System.out.println(Objects.equals(a, b)); // false
System.out.println(Objects.equals(null, null)); // true
Java

順序比較で null を許容するなら、先に null チェックのポリシー(null を最小/最大/不許可)を決め、コードに明示します。


実用例で身につける

例 1: スコア評価(しきい値の比較)

public class Grading {
    public static void main(String[] args) {
        int score = 78;
        String grade = score >= 80 ? "A" :
                       score >= 70 ? "B" :
                       score >= 60 ? "C" : "D";
        System.out.println(grade);
    }
}
Java

比較の順序は「上位から下位へ」。しきい値は重複のないように並べると読みやすく安全です。

例 2: 浮動小数点の近似比較

public class Approx {
    public static void main(String[] args) {
        double a = 0.1 + 0.2;
        double b = 0.3;
        double eps = 1e-9;
        boolean same = Math.abs(a - b) < eps;
        System.out.println(same); // true
    }
}
Java

近似比較を小さなユーティリティで統一すると、誤差の扱いがブレません。

例 3: 文字列の並び替え(比較関数)

import java.util.*;

public class SortByName {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("sato", "Abe", "tanaka");
        names.sort(String::compareTo); // 辞書順
        System.out.println(names);     // [Abe, sato, tanaka]
    }
}
Java

比較関数は「0/正/負」を返す compareTo を使うのが標準形です。大小の定義を一箇所にまとめると、バグの芽を摘めます。


仕上げのアドバイス(重要ポイントのまとめ)

== はプリミティブでは値比較、参照型では同一インスタンス比較。内容比較は常に equals(金額は BigDecimal.compareTo)。浮動小数点はイプシロンで近似比較し、NaN/Infinity は専用メソッドで判定。ラッパー型は == を避け、Objects.equals で null 安全に。比較の順序としきい値を明確に書き、境界条件をテストで覆う。これだけ押さえれば、比較に関する初学者のつまずきはほぼ消えます。

タイトルとURLをコピーしました