タイトル: String.equals
SEOタイトル: Java String.equals 完全ガイド(== との違い / NullPointerException 回避 / equalsIgnoreCase / Objects.equals)
| この記事の要点 |
|
String.equals とは
String.equals(Object obj) は文字列の中身(文字シーケンス)が等しいかを判定する Java のメソッドです。java.lang.Object の equals をオーバーライドし、参照ではなく内容で比較するように実装されています。
定義
| 修飾子と型 | メソッド | 説明 |
|---|---|---|
| boolean | equals(Object anObject) | 文字列の内容比較。大文字小文字は区別する |
| boolean | equalsIgnoreCase(String anotherString) | 大文字小文字を無視して内容比較 |
| boolean | contentEquals(CharSequence cs) | StringBuilder 等の CharSequence と比較 |
基本例
String a = "hello";
String b = "hello";
String c = new String("hello");
// == は参照比較(リテラルは文字列プールで同一参照)
System.out.println(a == b); // true
System.out.println(a == c); // false (new で別オブジェクト)
// equals は内容比較
System.out.println(a.equals(b)); // true
System.out.println(a.equals(c)); // true
System.out.println(a.equals("HELLO")); // false (大文字小文字区別あり)
// 大文字小文字を無視
System.out.println(a.equalsIgnoreCase("HELLO")); // true
== と equals の違い
| 演算 / メソッド | 比較対象 | 結果 |
|---|---|---|
== | 参照(メモリアドレス) | 同じオブジェクトか |
.equals() | 内容 | 同じ文字列か |
Java 初心者が最も間違える点。文字列リテラル同士は文字列プールで共有されるため == でも一致してしまうことがあり、誤動作に気づきにくいバグを生みます。文字列の比較は必ず equals。
NullPointerException の罠
変数が null のときに equals を呼び出すと NullPointerException(NPE)が発生します。
String str = null;
// NG: str が null だと NPE
if (str.equals("OK")) { ... } // NullPointerException!
// 良い書き方 1: 定数側を先に置く(Yoda 記法)
if ("OK".equals(str)) { ... } // str が null でも false で OK
// 良い書き方 2: 明示的に null チェック
if (str != null && str.equals("OK")) { ... }
// 良い書き方 3: Objects.equals (Java 7+)
if (java.util.Objects.equals(str, "OK")) { ... }
equalsIgnoreCase — 大文字小文字を無視
String userInput = "YES";
if (userInput.equalsIgnoreCase("yes")) {
System.out.println("はいと判定");
}
// 国際化の罠: トルコ語の I 問題
// "TITLE".toLowerCase() は "tıtle" になる場合あり
// equalsIgnoreCase は内部で Locale 非依存に比較されるので安全
Objects.equals — null 安全な比較
Java 7 で導入された Objects.equals(a, b) は、両方 null なら true、片方だけ null なら false、両方非 null なら a.equals(b) を呼びます。NPE の心配なし。
import java.util.Objects;
String a = null;
String b = null;
System.out.println(Objects.equals(a, b)); // true
System.out.println(Objects.equals(a, "hello")); // false
System.out.println(Objects.equals("hello", "hello")); // true
独自クラスでの equals 実装
独自クラスを HashSet / HashMap / List.contains 等で正しく扱うには、equals と hashCode をセットでオーバーライドします。
public class User {
private final String id;
private final String name;
public User(String id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User other = (User) o;
return Objects.equals(id, other.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
equals の規約(重要)
Object.equals をオーバーライドする際は、以下の5 つの規約を必ず守ります。
| 規約 | 意味 |
|---|---|
| 反射性 | x.equals(x) == true |
| 対称性 | x.equals(y) == y.equals(x) |
| 推移性 | x.equals(y) && y.equals(z) なら x.equals(z) |
| 一貫性 | 状態が変わらない限り、何度呼んでも同じ結果 |
| 非 null 性 | x.equals(null) == false |
パフォーマンス
String の equals は最初の文字から順に比較するため、文字数 N に対して最悪 O(N)。長文字列を頻繁に比較するときは、ハッシュコード(hashCode)でフィルタするか、intern() で文字列プールに登録して == で比較するなどの最適化を検討します。
FAQ
Q: 文字列を switch で分岐したい
A: Java 7 以降、switch (str) がサポートされており、内部的に equals が呼ばれます。null だと NPE になるので事前チェック必須。
Q: compareTo との違いは?
A: equals は等しいかを boolean で返す。compareTo は辞書順で int(負/0/正)を返し、ソートに使う。
関連
- String — 不変な文字列クラス
- StringBuilder — 可変な文字列クラス
- Objects.equals — null 安全な比較
- hashCode — equals とセットでオーバーライド
- compareTo — 順序比較