入門 ブラウザ 約12分

文字列の比較は == ではなく equals

文字列を == で比べると結果が書き方に左右される理由を実行結果で確かめ、equals による比較に切り替えるレッスン。

if 文で数値を比べたときは == を使いました。文字列も同じように書けてしまいますが、結果は書き方によって変わります。この回は、その理由と正しい比べ方を扱います。

実行環境は引き続きブラウザ上のもの(paiza.IOOneCompiler)です。

== で比べると、うまくいってしまう

うまくいく例から見ます。

public class Main {
  public static void main(String[] args) {
    String a = "Java";
    String b = "Java";

    if (a == b) {
      System.out.println("同じです");
    } else {
      System.out.println("違います");
    }
  }
}
同じです

ab の中身はどちらも Java で、== は成立しました。ここだけ見ると、文字列も == で比べられるように見えます。

中身が同じでも「違います」になる

次のコードは、b の作り方を変え、中身を確かめるために b を表示する行を足したものです。

public class Main {
  public static void main(String[] args) {
    String a = "Java";
    String head = "Ja";
    String b = head + "va";

    System.out.println(b);

    if (a == b) {
      System.out.println("同じです");
    } else {
      System.out.println("違います");
    }
  }
}
Java
違います

System.out.println(b)Java と表示しています。中身は Java で間違いありません。それでも == は「違います」と判定しました。

== が比べているもの

String の変数に入っているのは、文字そのものではなく「文字が置いてある場所」です。== は、その場所が同じかどうかを比べます。

  • コードに直接書いた "Java" は、内容が同じなら1つにまとめて使い回されます。1つ目の例で ab が同じ場所を指していたのはこのためです
  • head + "va" のように実行中に組み立てた文字列は、別の場所に新しく作られます。2つ目の例では場所が違い、== が成立しませんでした

分かれ目は「実行中に組み立てたかどうか」です。"Ja" + "va" のように書いた時点で中身が決まる式は、コードに直接書いたのと同じ扱いになり、== が成立します。2つ目の例が成立しないのは、head という変数を1つはさんで、実行中に組み立てているからです。

図にすると違いが見えます。1つ目の例では、矢印の先が1つです。

flowchart LR
  a1["変数 a"] --> box["Java"]
  b1["変数 b"] --> box

2つ目の例では、矢印の先が2つに分かれています。

flowchart LR
  a2["変数 a"] --> box1["Java"]
  b2["変数 b"] --> box2["Java"]

== が見ているのは矢印の先です。中身が同じでも、箱が分かれていれば成立しません。

書き方によって成立したりしなかったりする以上、== は中身を比べる用途には使えません。

equals で中身を比べる

中身を比べるには equals を使います。変更するのは if 文の1行だけです。

public class Main {
  public static void main(String[] args) {
    String a = "Java";
    String head = "Ja";
    String b = head + "va";

    System.out.println(b);

    if (a.equals(b)) {
      System.out.println("同じです");
    } else {
      System.out.println("違います");
    }
  }
}
Java
同じです

a.equals(b) は「a の中身と b の中身が同じか」を判定します。System.out.println(...) と同じで、. の左にあるものに対して命令する形です。ここでは System.out の代わりに a という文字列の変数が左に来ています。

文字列で「等しくない」を書くとき

文字列の条件を反転させたいときは、!= ではなく ! を条件の前に付けます。

public class Main {
  public static void main(String[] args) {
    String head = "ba";
    String answer = head + "nana";

    if (!answer.equals("apple")) {
      System.out.println("apple ではありません");
    }
  }
}
apple ではありません

! は「〜でない」という意味です。answer != "apple" と書いても文法上は通りますが、== と同じ理由で、比べているのは中身ではありません。

数値の == はそのままでよい

int のような数値の型は、変数に値そのものが入っています。場所ではなく値が入っているので、== で中身を比べられます。

public class Main {
  public static void main(String[] args) {
    int x = 100;
    int y = 50 + 50;

    if (x == y) {
      System.out.println("数値は == で比べられます");
    }
  }
}
数値は == で比べられます

y は計算して作った値ですが、== は成立します。これまでの if 文を書き直す必要はありません。

比べ方の使い分け

比べるもの使うもの
数値(int など)== / !=age >= 18count == 0
文字列(String)が同じかequalsname.equals("Aki")
文字列が違うか!equals!name.equals("Aki")

コードを読むときの見方

文字列の比較が出てきたら、次の順で確認します。

  1. 比べているのが数値か文字列か — 変数の型を見る
  2. 文字列なら equals になっているか== が使われていれば、そこが疑うところ
  3. 試すときは、変数をはさんで組み立てた値で比べる"Java" と直接書いた2つや、"Ja" + "va" のように書いた時点で中身が決まる式では == が成立してしまう。この回の head + "va" の形で試す

3番目は、AI が出したコードを確かめるときにも使えます。1回動いたことが、正しさの証明にならない場面があります。

次の回へ

次は配列です。同じ型の値をまとめて持ち、番号で取り出す形を扱います。for 文と組み合わせると、複数のデータをまとめて処理できるようになります。