Check If Two Arrays Are Equal in Java (equals, deepEquals)

Check if two arrays are equal in Java with Arrays.equals(), deepEquals(), mismatch() and compare(), and fix array equality in records, sets and tests.

Two int arrays with the same values compared with ==, equals() and Arrays.equals()

Two arrays are equal in Java when they have the same length and equal elements at every index, and we check that with Arrays.equals(), because the == operator and the array’s own equals() method compare only references. For 2D and nested arrays, Arrays.deepEquals() compares the inner arrays as well.

Array comparison shows up in unit tests, in cache checks that detect a changed result, and in the validation of checksums and file signatures stored as byte[]. Since Java 9, Arrays.mismatch() and Arrays.compare() also tell us where two arrays differ and which one comes first.

The following example checks the same two arrays in four ways.

int[] first = {1, 2, 3};
int[] second = {1, 2, 3};
boolean sameObject = first == second;                  // false
boolean viaEquals = first.equals(second);              // false, same as ==
boolean sameContent = Arrays.equals(first, second);    // true
int[][] gridA = {{1, 2}, {3}};
int[][] gridB = {{1, 2}, {3}};
boolean nested = Arrays.deepEquals(gridA, gridB);      // true

Notice that == and equals() return false for two arrays with identical values. The rest of the article covers the exact rules of Arrays.equals(), nested arrays, comparators, mismatch() and compare(), order-insensitive checks, and arrays inside records and tests.

1. Why == and equals() Return false for Equal Arrays

An array variable holds a reference to an array object. The == operator compares those references, so it returns true only when both variables point to the same array. Arrays do not override equals(), so first.equals(second) runs Object.equals(), which is the same reference check.

Two int arrays with the same values compared with ==, equals() and Arrays.equals()
Two separate arrays with the same values are equal only by content, which Arrays.equals() checks
int[] cached = {4, 5};
int[] alias = cached;
int[] copy = cached.clone();
boolean sameRef = cached == alias;              // true
boolean copyRef = cached == copy;               // false
boolean copyContent = Arrays.equals(cached, copy);   // true

The same rule makes arrays unusable as keys in a HashMap or elements of a HashSet, because hashCode() is also inherited from Object. A lookup with a second array that holds the same values does not find the entry.

2. When Two Arrays Are Equal in Java With Arrays.equals()

The Arrays.equals() method comes in one version per primitive type plus one for Object[]. It returns true when both arrays have the same length and each pair of elements at the same index is equal. Two null references are also equal.

  • The order matters, so {1, 2} and {2, 1} are not equal.
  • One null array and one non-null array are not equal, and no exception is thrown.
  • In an Object[], elements are compared with Objects.equals(), so null elements are allowed.
  • In a double[], elements are compared by their bit pattern, so NaN equals NaN, whereas 0.0 and -0.0 differ.
boolean order = Arrays.equals(new int[] {1, 2}, new int[] {2, 1});        // false
boolean length = Arrays.equals(new int[] {1, 2}, new int[] {1, 2, 0});    // false
boolean bothNull = Arrays.equals((int[]) null, (int[]) null);             // true
boolean oneNull = Arrays.equals(new int[0], null);                        // false
boolean nullItems = Arrays.equals(new String[] {"a", null}, new String[] {"a", null});   // true
boolean nan = Arrays.equals(new double[] {Double.NaN}, new double[] {Double.NaN});       // true
boolean zeros = Arrays.equals(new double[] {0.0}, new double[] {-0.0});                  // false

Since Java 9, an overload compares only a range of each array, with the end index exclusive. A file upload service can use it to check the magic bytes at the start of a file without copying the first bytes into a new array.

byte[] pngSignature = {(byte) 0x89, 'P', 'N', 'G'};
byte[] upload = {(byte) 0x89, 'P', 'N', 'G', 13, 10, 26, 10};
boolean isPng = Arrays.equals(upload, 0, 4, pngSignature, 0, 4);   // true

For passwords, tokens and MAC values, we use MessageDigest.isEqual() instead of Arrays.equals(). Arrays.equals() returns at the first different byte, so the response time leaks how many leading bytes matched, and MessageDigest.isEqual() examines every byte, so its running time depends only on the array length.

byte[] expectedMac = {7, 1, 9};
byte[] receivedMac = {7, 1, 9};
boolean valid = MessageDigest.isEqual(expectedMac, receivedMac);   // true

3. Comparing Nested Arrays With Arrays.deepEquals()

For a 2D array, Arrays.equals() compares the rows with equals(), which is the reference check from section 1. Arrays.deepEquals() compares the rows by content, at any depth, and it also handles an Object[] that mixes arrays and other values.

int[][] seatsA = {{1, 0}, {0, 1}};
int[][] seatsB = {{1, 0}, {0, 1}};
boolean shallow = Arrays.equals(seatsA, seatsB);        // false, rows compared by reference
boolean deep = Arrays.deepEquals(seatsA, seatsB);       // true
Object[] mixedA = {"id", new int[] {7}};
Object[] mixedB = {"id", new int[] {7}};
boolean mixed = Arrays.deepEquals(mixedA, mixedB);      // true

The deepEquals() method takes Object[] parameters, so a one-dimensional primitive array does not fit. We use Arrays.equals() for an int[] and deepEquals() for int[][] and deeper arrays.

// does not compile: int[] cannot be converted to Object[]
boolean wrong = Arrays.deepEquals(new int[] {1}, new int[] {1});

4. Custom Element Equality With a Comparator

Java 9 added an Arrays.equals() overload that takes a Comparator. Two elements count as equal when the comparator returns 0, which lets us ignore case in strings or compare objects that do not override equals().

String[] tagsA = {"Java", "SQL"};
String[] tagsB = {"java", "sql"};
boolean exact = Arrays.equals(tagsA, tagsB);                                    // false
boolean ignoreCase = Arrays.equals(tagsA, tagsB, String.CASE_INSENSITIVE_ORDER);   // true

Say a class from a library, such as a Point with public fields, has no equals() method. A comparator built with Comparator.comparing() compares the fields we care about.

static class Point {
    final int x;
    final int y;
    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}
Point[] routeA = {new Point(0, 0), new Point(2, 3)};
Point[] routeB = {new Point(0, 0), new Point(2, 3)};
boolean byEquals = Arrays.equals(routeA, routeB);      // false, no equals() override
Comparator<Point> byXY = Comparator.<Point>comparingInt(p -> p.x).thenComparingInt(p -> p.y);
boolean byFields = Arrays.equals(routeA, routeB, byXY);   // true

5. Finding Where Two Arrays Differ With Arrays.mismatch()

A boolean tells us that two arrays differ but not where. Arrays.mismatch() (Java 9) returns the index of the first difference, or -1 when the arrays are equal. When one array is a prefix of the other, it returns the length of the shorter array.

int[] expected = {10, 20, 30, 40};
int[] actual = {10, 20, 35, 40};
int firstDiff = Arrays.mismatch(expected, actual);                     // 2
int same = Arrays.mismatch(expected, expected.clone());                // -1
int prefix = Arrays.mismatch(new int[] {1, 2}, new int[] {1, 2, 3});   // 2

A data import job that compares yesterday’s export with today’s can log the first changed position instead of only reporting that the files differ. The method throws NullPointerException for a null array, so we check for null first when the input can be missing.

6. Ordering Arrays With Arrays.compare()

Arrays.compare() (Java 9) compares two arrays element by element, the way String.compareTo() compares characters. The first different element decides the result, and when one array is a prefix of the other, the shorter array comes first.

int[] v1 = {1, 10, 0};
int[] v2 = {1, 9, 3};
int versions = Arrays.compare(v1, v2);                          // 1, v1 is greater
int shorter = Arrays.compare(new int[] {1, 2}, new int[] {1, 2, 0});   // -1
int equal = Arrays.compare(new int[] {5}, new int[] {5});              // 0

The first line compares version numbers 1.10.0 and 1.9.3 correctly, which string comparison gets wrong because the text “1.10.0” sorts before “1.9.3”. A result of 0 means equal content, the same as Arrays.equals() returning true.

7. Checking Equality While Ignoring Order

Sometimes only the elements matter, for example when two services return the same permissions in a different order. We sort copies of both arrays and compare the copies, which keeps the original arrays unchanged and also handles duplicates correctly.

static boolean sameElements(int[] a, int[] b) {
    if (a == null || b == null || a.length != b.length) {
        return a == b;
    }
    int[] x = a.clone();
    int[] y = b.clone();
    Arrays.sort(x);
    Arrays.sort(y);
    return Arrays.equals(x, y);
}
boolean anyOrder = sameElements(new int[] {3, 1, 2}, new int[] {1, 2, 3});   // true
boolean counts = sameElements(new int[] {1, 1, 2}, new int[] {1, 2, 2});     // false

Sorting costs O(n log n). Converting both arrays to a Set is a common shortcut, but a set drops duplicates, so {1, 1, 2} and {1, 2, 2} would wrongly count as equal. To check only whether one value is present, the guide on how to check if an array contains an item is the better fit.

8. Arrays Inside Records, Sets and Unit Tests

Records have the same reference problem with array components. A record generates equals() and hashCode() from its components, and for an array component, it compares the references. Two records with the same values are therefore not equal.

record Sample(String name, int[] values) {}
Sample s1 = new Sample("temp", new int[] {20, 21});
Sample s2 = new Sample("temp", new int[] {20, 21});
boolean recordsEqual = s1.equals(s2);          // false

We fix it by overriding both methods with Arrays.equals() and Arrays.hashCode(), following the equals() and hashCode() contract. Without the matching hashCode(), the record would still fail in a HashSet.

record Reading(String sensor, int[] values) {
    @Override
    public boolean equals(Object o) {
        return o instanceof Reading r && sensor.equals(r.sensor) && Arrays.equals(values, r.values);
    }
    @Override
    public int hashCode() {
        return 31 * sensor.hashCode() + Arrays.hashCode(values);
    }
}
boolean fixed = new Reading("t1", new int[] {5}).equals(new Reading("t1", new int[] {5}));   // true
Set<Reading> unique = new HashSet<>(List.of(new Reading("t1", new int[] {5})));
boolean found = unique.contains(new Reading("t1", new int[] {5}));                         // true

In JUnit 5 tests, assertEquals() on two arrays compares references and fails. We use assertArrayEquals(), which compares the contents and also handles nested arrays, and its failure message shows the first index that differs.

9. Choosing an Array Comparison Method

Each method checks a different property of two arrays.

QuestionMethodSince
Same array object?a == b1.0
Same length and elements, one dimension?Arrays.equals(a, b)1.2
Same content in 2D or nested arrays?Arrays.deepEquals(a, b)1.5
Equal by a custom rule?Arrays.equals(a, b, comparator)9
Equal in a range?Arrays.equals(a, from, to, b, from, to)9
Where is the first difference?Arrays.mismatch(a, b)9
Which array sorts first?Arrays.compare(a, b)9
Equal secrets without a timing leak?MessageDigest.isEqual(a, b)1.1

Every Arrays method in the table runs in O(n) time and stops at the first difference, whereas MessageDigest.isEqual() reads the whole input on purpose and == compares only two references.

10. Array Equality FAQs

Most questions about comparing arrays in Java are about order, length, primitive types and the Arrays class.

10.1. Does Arrays.equals() check the order of elements?

Yes. It compares the elements index by index, so the same values in a different order are not equal. To ignore order, we sort copies first, as in section 7.

10.2. Can we compare arrays of different lengths?

Yes. Arrays.equals() returns false for different lengths without an exception. Arrays.mismatch() returns the shorter length when one array is a prefix of the other, and Arrays.compare() puts the shorter prefix first.

10.3. How do we compare two arrays without the Arrays class?

We check both references for null, compare the lengths, and loop over the indexes, returning false at the first pair that differs. For objects, we compare elements with Objects.equals() so null elements do not throw NullPointerException.

10.4. How do we compare an int array with an Integer array?

We convert one of them first, for example with Arrays.stream(ints).boxed().toArray(Integer[]::new), and compare the two Integer[] arrays. The guide on primitive and object array conversion has the other direction.

11. Conclusion

The == operator and equals() compare array references, so for content we call Arrays.equals(), and for nested arrays, Arrays.deepEquals(). Both are null-safe and compare elements in order.

Java 9 added comparator and range overloads, mismatch() for the first different index and compare() for ordering. Records and classes with array fields need their own equals() and hashCode(), and secrets need the constant-time MessageDigest.isEqual().

12. References

Happy Learning !!

Source Code on Github

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.