1. 概要

このチュートリアルでは、Javaの配列を比較するさまざまな方法を見ていきます。 従来の方法について説明し、 lambda expressionを使用した例もいくつか示します。

2. アレイの比較

Javaの配列を比較します。ご存知のとおり、これらはオブジェクトです。 したがって、いくつかの基本的な概念を更新しましょう。

  • オブジェクトには参照と値があります
  • 2つの等しい参照は同じ値を指す必要があります
  • 2つの異なる値は異なる参照を持つ必要があります
  • 2つの等しい値は、必ずしも同じ参照を持つとは限りません
  • プリミティブ値は、値ごとにのみ比較されます
  • 文字列リテラルは値ごとにのみ比較されます

2.1. オブジェクト参照の比較

同じ配列を指す2つの参照がある場合、==演算子との等式比較で常に真の結果が得られるはずです。

例を見てみましょう:

String[] planes1 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };
String[] planes2 = planes1;

まず、planets1によって参照される平面モデルの配列を作成しました。 次に、planets1を参照するplanes2を作成します。 これにより、メモリ内の同じ配列への2つの参照を作成しています。 したがって、「planes1==planes2」式はtrueを返します。

配列の場合、equals()メソッドは==演算子と同じです。 したがって、 planets1.equals(planes2)は、両方の参照が同じオブジェクトを参照しているため、trueを返します。 一般的に、 array1.eqauls(array2)は、式 array1 == array2″ がを返す場合にのみ、trueを返します。 X152X]true。

2つの参照が同じであるかどうかを主張しましょう。

assertThat(planes1).isSameAs(planes2);

ここで、planets1によって参照される値が実際にplanes2によって参照される値と同じであることを確認しましょう。 したがって、 planets2、によって参照される配列を変更し、その変更がplanets1によって参照される配列に影響を与えるかどうかを確認できます。

planes2[0] = "747";

最終的にこれが機能することを確認するために、アサーションを作成しましょう。

assertThat(planes1).isSameAs(planes2);
assertThat(planes2[0]).isEqualTo("747");
assertThat(planes1[0]).isEqualTo("747");

この単体テストでは、2つのアレイを参照して比較することができました。

ただし、 1つの参照が別の値に割り当てられると、同じ値を参照することを証明しただけです。

次に、同じ値で2つの異なる配列を作成します。

String[] planes1 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };
String[] planes2 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };

それらは異なるオブジェクトであるため、同じではないことは確かです。 したがって、それらを比較することができます。

assertThat(planes1).isNotSameAs(planes2);

要約すると、この場合、メモリ内に同じString値をまったく同じ順序で含む2つの配列があります。 ただし、参照される配列の内容が異なるだけでなく、参照自体も異なります。

2.2. 配列の長さの比較

配列の長さは、要素タイプの に関係なく、またはそれらの値がに入力されているかどうかに関係なく比較できます。

2つの配列を作成しましょう:

final String[] planes1 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };
final Integer[] quantities = new Integer[] { 10, 12, 34, 45, 12, 43, 5, 2 };

これらは、要素タイプが異なる2つの異なる配列です。 このデータセットでは、例として、各モデルの飛行機が倉庫に保管されている数を登録しています。 それらに対して単体テストを実行してみましょう。

assertThat(planes1).hasSize(8);
assertThat(quantities).hasSize(8);

これにより、両方の配列に8つの要素があり、lengthプロパティが各配列に対して正しい数の要素を返すことが証明されました。

2.3. 配列とArrays.equalsの比較

これまでは、オブジェクトIDに基づいて配列を比較するだけでした。 一方で、 2つの配列が内容に関して等しいかどうかを確認するために、JavaはArrays.equals静的メソッドを提供します。 このメソッドは、並列の位置ごとに配列を反復処理し、==演算子を適用します。 要素のすべてのペアに対して

同じStringリテラルを使用して、まったく同じ順序で2つの異なる配列を作成してみましょう。

String[] planes1 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };
String[] planes2 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };

そして今、それらが等しいと主張しましょう:

assertThat(Arrays.equals(planes1, planes2)).isTrue();

2番目の配列の値の順序を変更すると、次のようになります。

String[] planes1 = new String[] { "A320", "B738", "A321", "A319", "B77W", "B737", "A333", "A332" };
String[] planes2 = new String[] { "B738", "A320", "A321", "A319", "B77W", "B737", "A333", "A332" };

別の結果が得られます。

assertThat(Arrays.equals(planes1, planes2)).isFalse();

2.4. 配列とArrays.deepEqualsの比較

Java で単純型を使用している場合、==演算子の使用は簡単です。 これらは、プリミティブ型またはStringリテラルである可能性があります。 Objectの配列間の比較はより複雑になる可能性があります。 この背後にある理由は、Arrays.deepEqualsの記事で詳しく説明されています。 例を見てみましょう。

まず、プレーンクラスから始めましょう。

public class Plane {
    private final String name;
    private final String model;

    // getters and setters
}

そして、hashCodeおよびequalsメソッドを実装しましょう。

@Override
public boolean equals(Object o) {
    if (this == o)
        return true;
    if (o == null || getClass() != o.getClass())
        return false;
    Plane plane = (Plane) o;
    return Objects.equals(name, plane.name) && Objects.equals(model, plane.model);
}

@Override
public int hashCode() {
    return Objects.hash(name, model);
}

次に、次の2要素配列を作成しましょう。

Plane[][] planes1 
  = new Plane[][] { new Plane[]{new Plane("Plane 1", "A320")}, new Plane[]{new Plane("Plane 2", "B738") }};
Plane[][] planes2 
  = new Plane[][] { new Plane[]{new Plane("Plane 1", "A320")}, new Plane[]{new Plane("Plane 2", "B738") }};

それらが真の、深く等しい配列であるかどうかを見てみましょう。

assertThat(Arrays.deepEquals(planes1, planes2)).isTrue();

比較が期待どおりに機能することを確認するために、最後の配列の順序を変更してみましょう。

Plane[][] planes1 
  = new Plane[][] { new Plane[]{new Plane("Plane 1", "A320")}, new Plane[]{new Plane("Plane 2", "B738") }};
Plane[][] planes2 
  = new Plane[][] { new Plane[]{new Plane("Plane 2", "B738")}, new Plane[]{new Plane("Plane 1", "A320") }};

最後に、それらが実際にもはや等しくないかどうかをテストしましょう。

assertThat(Arrays.deepEquals(planes1, planes2)).isFalse();

2.5. 要素の順序が異なる配列の比較

要素の順序に関係なく、配列が等しいかどうかを確認するには、平面の1つのインスタンスを一意にするを定義する必要があります。 私たちの場合、ある平面が別の平面とは異なることを判断するには、別の名前またはモデルで十分です。 これは、hashCodeequalsメソッドの両方をすでに実装していることで確立されています。 これは、配列を比較する前に、配列を並べ替える必要があることを意味します。 そのためには、コンパレータが必要です。

Comparator<Plane> planeComparator = (o1, o2) -> {
    if (o1.getName().equals(o2.getName())) {
        return o2.getModel().compareTo(o1.getModel());
    }
    return o2.getName().compareTo(o1.getName());
};

このコンパレータでは、名前を優先しています。 名前が等しい場合は、モデルを調べてあいまいさを解決します。 タイプStringcompareToメソッドを使用して文字列を比較します。

並べ替え順序に関係なく、配列が等しいかどうかを確認できるようにする必要があります。 そのために、配列を並べ替えてみましょう。

Arrays.sort(planes1[0], planeComparator);
Arrays.sort(planes2[0], planeComparator);

そして最後に、それらをテストしましょう:

assertThat(Arrays.deepEquals(planes1, planes2)).isTrue();

最初に同じ順序で配列を並べ替えたので、deepEqualsメソッドでこれら2つの配列が等しいかどうかを確認できます。

3. 結論

このチュートリアルでは、配列を比較するさまざまな方法を見てきました。 次に、参照と値の比較の違いを確認しました。 さらに、配列を深く比較する方法を調べました最後に、equalsdeepEqualsを使用した通常の比較と深い比較の違いを確認しました。それぞれ

いつものように、例の完全なソースコードはGitHubで入手できます。