【Java学習|実務向け】Java開発で必須の配列比較:Arrays.equals() と Arrays.deepEquals() の使い分けをマスターする

1. 導入:なぜ配列の比較は「==」ではいけないのか

Javaにおいて、配列の比較で「==」演算子を使ってはいけないことは、現場のエンジニアであれば誰もが一度は教わる基本です。配列に対して「==」を使用すると、中身の値ではなく「メモリ上の参照先」が比較されるため、値が同じであっても結果は常にfalseになります。
本記事では、配列の中身を正しく比較するためのArrays.equals()と、多次元配列や複雑なオブジェクト構造に対応したArrays.deepEquals()の使い分け、そして現代的なJava開発における注意点を解説します。

2. 基礎知識:比較メソッドの仕組み

Javaのjava.util.Arraysクラスには、配列比較のための強力なメソッドが用意されています。

Arrays.equals(Object[] a, Object[] b)
1次元配列の比較に使用します。各要素のequals()メソッドが呼び出され、全ての要素が一致すればtrueを返します。

Arrays.deepEquals(Object[] a, Object[] b)
多次元配列(配列の中に配列がある構造)の比較に使用します。要素の中に配列が含まれている場合、再帰的に中身を比較します。

3. 実装/解決策:用途に応じた使い分け

現場では、単なるプリミティブ配列だけでなく、StringやRecord型、さらにはOptionalを保持する配列を扱う場面も多いでしょう。ここで重要なのは、「どの深さまで比較する必要があるか」を判断することです。

4. サンプルプログラム

以下のコードは、実務で頻出するパターンを網羅したサンプルです。

import java.util.Arrays;
import java.util.Optional;

public class ArrayComparisonExample {
// レコード型の定義(Java 14以降)
public record User(int id, String name) {}

public static void main(String[] args) {
// 1. 1次元配列の比較 (StringやRecordはequalsが適切に実装されているためこれでOK)
User[] users1 = {new User(1, “Alice”), new User(2, “Bob”)};
User[] users2 = {new User(1, “Alice”), new User(2, “Bob”)};

System.out.println(“1次元配列の比較: ” + Arrays.equals(users1, users2)); // true

// 2. 多次元配列の比較 (deepEqualsが必要)
String[][] matrix1 = {{“A”, “B”}, {“C”, “D”}};
String[][] matrix2 = {{“A”, “B”}, {“C”, “D”}};

// Arrays.equals(matrix1, matrix2) だと false になるため注意
System.out.println(“多次元配列のdeepEquals: ” + Arrays.deepEquals(matrix1, matrix2)); // true

// 3. Optionalを含む配列の比較
Optional[] optArray1 = new Optional[]{Optional.of(“Java”), Optional.empty()};
Optional[] optArray2 = new Optional[]{Optional.of(“Java”), Optional.empty()};

System.out.println(“Optional配列の比較: ” + Arrays.equals(optArray1, optArray2)); // true
}
}

5. 応用・注意点:現場で陥りやすい罠

StringBuilderの比較について
現場で非常に多いミスが、StringBuilderを配列に入れて比較するケースです。StringBuilderクラスは、java.lang.Objectのequals()メソッドをオーバーライドしていません。つまり、StringBuilderオブジェクト同士を比較すると、内容(文字列)ではなく「インスタンスの同一性」が問われます。
配列内のStringBuilderを比較する場合は、一度Stream API等でStringに変換してから比較するか、Listに変換してから比較することを強く推奨します。

nullの取り扱い
Arrays.equals()やdeepEquals()は、引数にnullが渡された場合、NullPointerExceptionをスローします。比較を行う前には、java.util.Objects.equals()や、Apache Commons LangのEqualsBuilderなどを活用し、null安全なコードを心がけましょう。

まとめ
・1次元配列なら Arrays.equals()
・2次元以上の配列なら Arrays.deepEquals()
・StringBuilderや、equalsが未実装のクラスが要素に含まれる場合は、そのまま比較せず変換を検討する

これらを意識するだけで、配列比較に起因する予期せぬバグを大幅に減らすことができます。

コメント

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