はじめに
現在、Javaを使用した仕事をしていますが、Integerのような変数に対して比較方法が間違いやすいと思い、バグの原因になる可能性が高いと思ったので、少し整理してみようと思います。
ラッパークラスについて
ラッパークラス(Wrapper Class)は、int、booleanなどのプリミティブデータ型(Primitive Data Type)をオブジェクトとして使用するためのクラスです。
プリミティブデータ型とラッパークラスの対応は以下のようになります。
| プリミティブデータ型 | ラッパークラス |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| boolean | Boolean |
| char | Character |
「==」 と 「equals」
「==」を使用した比較
「==」はプリミティブデータ型の比較で使います。
ラッパークラスをプリミティブデータ型に変換(intValueなど)して比較することも可能です。
int intNum1 = 1000;
int intNum2 = 1000;
Integer integerNum1 = 1000;
Integer integerNum2 = 1000;
System.out.println(intNum1 == intNum2); // true
System.out.println(integerNum1.intValue() == integerNum2.intValue()); // true
JDK1.5以上でプリミティブデータ型とラッパークラスを==で比較するとき、コンパイラーが自動に方を変換して比較するため、==を使用することも可能です。
しかし、コンパイラー内部で追加処理が行い、性能に影響を与えるため、データ型を合わせたほうが良いです。
int intNum1 = 1000;
Integer integerNum1 = 1000;
System.out.println(intNum1 == integerNum1); // true
ラッパークラスとラッパークラスの比較で==を使用する場合、ラッパークラスの参照先が同じかどうかを比較するため、正しい結果を得られません。
Integer型はIntegerCache機能のため、値が-128 ~ 127である場合、==で比較も可能ではありますが、個人的には控えたいですね。
Integer integerNum1 = 128;
Integer integerNum2 = 128;
Integer integerNum3 = 127;
Integer integerNum4 = 127;
System.out.println(integerNum1 == integerNum2); // false
System.out.println(integerNum3 == integerNum4); // true
「equals」を使用した比較
ラッパークラスの比較に「==」を使用しないなら、どのような方法で比較するんでしょうか?
ラッパークラスのような参照型を比較する場合は、「equals」メソッドを使用します。
Integer integerNum1 = 1000;
Integer integerNum2 = 1000;
System.out.println(integerNum1.equals(integerNum2)); // true
しかし、プリミティブデータ型はequalsを使用できません。
int intNum1 = 1000;
int intNum2 = 1000;
System.out.println(intNum1.equals(intNum2)); // エラーが発生する
その他
「Objects.equals」を使用した比較
Integerのようなラッパークラスの変数は値がnullである可能性もあります。
その場合、値がnullである変数から「equals」を使用するとNullPointerExceptionが発生します。
Integer integerNum1 = 1000;
Integer integerNum2 = null;
System.out.println(integerNum1.equals(integerNum2)); // false (エラー発生しない)
System.out.println(integerNum2.equals(integerNum1)); // NullPointerExceptionが発生する
そのように変数の値がnullになる可能性がある場合、NullPointerExceptionを防ぐため、「Objects.equals」を使用する方法もあります。
// import java.util.Objects;
int intNum1 = 1000;
int intNum2 = 1000;
Integer integerNum1 = 1000;
Integer integerNum2 = 1000;
Integer nullNum1 = null;
Integer nullNum2 = null;
System.out.println(Objects.equals(intNum1, intNum2)); // true
System.out.println(Objects.equals(integerNum1, integerNum2)); // true
System.out.println(Objects.equals(nullNum1, nullNum2)); // true (両方nullの場合はtrue)
System.out.println(Objects.equals(intNum1, nullNum1)); // false (NullPointerExceptionが発生しない)
System.out.println(Objects.equals(nullNum2, integerNum2)); // false (NullPointerExceptionが発生しない)
おわりに
Javaを使用するときの基本的な内容だと思いますが、間違いやすいところだと思ったので、比較で使用する「==」、「equals」、そして「Objects.equals」について整理しました。
結論を言うと、
- プリミティブデータ型の比較では「==」を使用する。
- ラッパークラスの比較では「equals」を使用する。
- 比較対象の値がnullの可能性がある場合は「Objects.equals」を使用する。
でまとめられると思います。