Tuesday, August 24, 2021

How to Compare Arrays in Java – Equals vs deepEquals Example

java.util.Arrays class provides equals() and deepEquals() method to compare two Arrays in Java. Both of these are overloaded methods to compare primitive arrays e.g. int, long, float, double, and Object arrays e.g. Arrays.equals(Object[], Object[]). Arrays.equals() returns true if both Arrays which it is comparing are null If both arrays pointing to the same Array Object or they must be of the same length and contains the same element in each index. In all other cases, it returns false. Arrays.equals() calls equals() method of each Object while comparing Object arrays.

One of the tricky questions in Java related to Array comparison is the Difference between Arrays.equals() and Arrays.deepEquals() method.  Since both equals and deepEquals are used for array comparison, what is the difference between them that becomes important? 

The short answer to this question is that Array's equals() method does not perform deep comparison and fails logical comparison in the case of nested Array,  on the other hand, deepEquals() perform deep comparison and returns logical comparison in case of a nested array.



Difference between equals and deepEquals of Arrays in Java

As I said earlier, the difference between deepEquals() vs equals() method is a good Java Interview question and the main difference between them comes while comparing nested array i.e. Array inside Array. Arrays.equals() method does not compare recursively if an array contains another array.

On the other hand Arrays.deepEquals() method compares recursively if an array contains another array. Arrays.equals() check is if the element is null or not and then calls equals() method, it does not check for Array type. 



This means if any item in the array is another array itself then call to equals() goes to default java.lang.Object equals(), which compares reference of two Objects and does not perform the logical comparison and can return false even if two object arrays are logically equaled, as seen in the following Object Array comparison. 

On the other hand Arrays.deepEquals() method performs a lot of checks and calls Arrays.equals() for non-array comparison and recursively calls Arrays.deepEquals() for array type comparison, which allows it to compare nested array logically in Java. 


It's better to use Arrays.equals() to compare non-nested Array and Arrays.deepEquals() to compare nested Array, as the former is faster than later in the case of non-nested Array.

This is quite clear with following code snippet from Arrays.equals() method of java.util.Arrays class :

for (int i=0; i<length; i++) {
            Object o1 = a[i];
            Object o2 = a2[i];
            if (!(o1==null ? o2==null : o1.equals(o2)))
                return false;
 }

 You can see that equals() method of java.util.Arrays class does not check if element is Array type or not and simply calls equals(), which in case of array act similar to == operator. Now let's see Arrays.deepEquals() code from java.util.Arrays class :

for (int i = 0; i < length; i++) {
            Object e1 = a1[i];
            Object e2 = a2[i];

if (e1 instanceof Object[] && e2 instanceof Object[])
    eq = deepEquals ((Object[]) e1, (Object[]) e2);
else if (e1 instanceof byte[] && e2 instanceof byte[])
    eq = equals((byte[]) e1, (byte[]) e2);
else
     eq = e1.equals(e2);

}

How to compare Arrays in Java - Equals vs DeepEquals ExampleArrays.deepEquals() calls deepEquals() recursively if one of element is of type Object[]. I have not included complete code but you can check the complete code of java.util.Arrays class in Eclipse IDE by using Eclipse shortcut Ctrl + T as discussed in Top 30 Eclipse shortcuts for Java programmers. Even after pressing Ctrl+T you only see the class file and not the Java source then you need to attach the JDK source code with rt.jar. See Eclipse tutorial How to attach source in Eclipse for any JAR to learn more about attaching source in Eclipse.



Array Comparison Example using equals() and deepEquals()

In this section, we will see a couple of examples of comparing arrays in Java. We will compare both primitive and object arrays as well as a nested arrays to see How array comparison works. Primitive and Object arrays are compared using the Arrays.equals() method while the nested array is compared using Arrays.deepEquals() method to get logical comparison.

import java.util.Arrays;

/**
 *
 * Java program to compare two Arrays in Java to see if they are equal or not.
 * We will example of comparing both primitive array e.g. int, long or double array
 * and Object array e.g. String array to see if they are equal or not.
 *
 * @author http://javarevisited.blogspot.com
 */

public class ArrayCompareTest {

    public static void main(String args[]) {
     
       //comparing primitive int arrays in Java
        int[] i1 = new int[] {1,2,3,4};
        int[] i2 = new int[] {1,2,3,4};
        int[] i3 = new int[] {0,2,3,4};
     
        //Arrays.equals() compare Array and return true if both array are equal
        //i..e either both of them are null or they are identical in length, and each pair
        //match each other e.g. i[0]=i2[0], i[1]=i2[1] and so on
     
        //i1 and i2 should be equal as both contains same elements
        boolean result = Arrays.equals(i1, i2);
        System.out.println("Comparing int array i1: " + Arrays.toString(i1)
                            + " and i1: " + Arrays.toString(i2));
        System.out.println("Does array i1 and i2 are equal : " + result);
     
        //array ii2 and i3 are not equals as only length is same, first pair is not same
        result = Arrays.equals(i2, i3);
        System.out.println("Comparing int array i2: " + Arrays.toString(i2)
                            + " and i3: " + Arrays.toString(i3));
        System.out.println("Does array i2 and i3 are equal : " + result);
     
        //comparing floating point or double arrays in Java
        double[] d1 = new double[] {1.5, 2.4, 3.2, 4,1};
        double[] d2 = new double[] {1.5, 2.4, 3.2, 4,1};
        double[] d3 = new double[] {0.0, 2.4, 3.2, 4,1};
     
        //Comparing two floating-point arrays using Arrays.equals() in Java
     
        //double array d1 and d2 should be equal - length same, each index matches
        result = Arrays.equals(d1, d2);
        System.out.println("Comparing double array d1: " + Arrays.toString(d1)
                            + " and d2: " + Arrays.toString(d2));
        System.out.println("Does double array d1 and d2 are equal : " + result);
     
        //double array d2 and d3 is not equal - length same, first pair does not match
        result = Arrays.equals(d2, d3);
        System.out.println("Comparing double array d2: " + Arrays.toString(d2)
                            + " and d3: " + Arrays.toString(d3));
        System.out.println("Does double array d2 and d3 are same : " + result);
     
        //comparing Object array, here we will use String array
        String[] s1 = new String[]{"One", "Two", "Three"};
        String[] s2 = new String[]{"One", "Two", "Three"};
        String[] s3 = new String[]{"zero", "Two", "Three"};
     
        //String array s1 and s2 is equal - length same, each pair matches
        result = Arrays.equals(s1, s2);
        System.out.println("Comparing two String array s1: " + Arrays.toString(s1)
                            + " and s2: " + Arrays.toString(s2));

        System.out.println("Are both String array s1 and s2 are equal : " + result);
     
        //String array s2 and s3 is not equal - length same, first pair different
        result = Arrays.equals(d2, d3);
        System.out.println("Comparing two String array s2: " + Arrays.toString(s2)
                             + " and s3: " + Arrays.toString(s3));

        System.out.println("Are both String array s2 and s3 are equal : " + result);
     
        //Comparing nested arrays with equals and deepEquals method
        //Arrays.equals() method does not compare recursively,
        //while deepEquals() compare recursively
        //if any element inside Array is type of Array itself,
        //as here second element is String array
       
        Object[] o1 = new Object[]{"one", new String[]{"two"}};
        Object[] o2 = new Object[]{"one", new String[]{"two"}};
     
        System.out.println("Object array o1: " + Arrays.toString(o1) + " and o2: "
                            + Arrays.toString(o2));
        System.out.println("Comparing Object Array o1 and o2 with Arrays.equals : "
                            + Arrays.equals(o1, o2));
        System.out.println("Comparing Object Array o1 and o2 with Arrays.deepEquals : "
                            + Arrays.deepEquals(o1, o2));
    }
 
}

Output:
Comparing int array i1: [1, 2, 3, 4] and i1: [1, 2, 3, 4]
Does array i1 and i2 are equal : true
Comparing int array i2: [1, 2, 3, 4] and i3: [0, 2, 3, 4]
Does array i2 and i3 are equal : false
Comparing double array d1: [1.5, 2.4, 3.2, 4.0, 1.0] and d2: [1.5, 2.4, 3.2, 4.0, 1.0]
Does double array d1 and d2 are equal : true
Comparing double array d2: [1.5, 2.4, 3.2, 4.0, 1.0] and d3: [0.0, 2.4, 3.2, 4.0, 1.0]
Does double array d2 and d3 are same : false
Comparing two String array s1: [One, Two, Three] and s2: [One, Two, Three]
Are both String array s1 and s2 are equal : true
Comparing two String array s2: [One, Two, Three] and s3: [zero, Two, Three]
Are both String array s2 and s3 are equal : false
Object array o1: [one, [Ljava.lang.String;@19821f] and o2: [one, [Ljava.lang.String;@addbf1]
Comparing Object Array o1 and o2 with Arrays.equals : false
Comparing Object Array o1 and o2 with Arrays.deepEquals : true

That's all on how to compare two arrays in Java. We have seen an example of comparing both primitive and object array and also seen the difference between equals() and deepEquals() method of Arrays class

In summary use Arrays.equals() for comparing non-nested arrays, it has an overloaded method for primitive array and performs better than deepEquals() but always use deepEquals() method to compare nested array in Java to get the logical comparison.


Other Java Collection tutorials you may like

5 comments:

  1. I am looking for a way to compare Array elements to each other and find out How many elements or indexes are equals and How many elements are not equal? is there a way I can compare Array values in Java ?

    ReplyDelete
  2. @Anonymous Nice question here's the solution for your query..

    what you expect is that for example.. Java code that can compare in this way :

    <1 2 3 4> = <3 1 2 4>
    <1 2 3 4> != <3 4 1 1>


    simple quadratic solution (which your original attempt is), is fine. In that case, you can do something like this:

    int count(int[] nums, int x) {
    int count = 0;
    for (int num : nums) {
    if (num == x) count++;
    }
    return count;
    }
    boolean equals(int[] arr1, int[] arr2) {
    if (arr1.length != arr2.length) return false;
    for (int x : arr1) {
    if (count(arr1, x) != count(arr2, x)) return false;
    }
    return true;
    }
    This sacrifices speed for clarity: it's obviously correct!!

    Tips

    Use for-each whenever applicable; it always read to better readability
    Helper functions improve both readability and reusability!

    ReplyDelete
  3. int[] i2 = new int[] {1,2,3,4};
    int[] i3 = new int[] {1,2,3,0};
    boolean result;

    could you please explain the difference between below two statements?

    result = Arrays.equals(i2, i3);
    result = i2==i3;

    ReplyDelete
  4. You've written "Arrays.equals() returns true if both Arrays which it is comparing are null", but its giving error "The method equals(long[], long[]) is ambiguous for the type Arrays". Does it specific to java version?

    System.out.println(Arrays.equals(null,null));

    ReplyDelete
  5. @Ganesh, your code is matching to Arrays.equals(long, long) by compiler, hence its giving the error.

    Try this

    Object[] first = null;
    Object[] second = null;

    System.out.println(Arrays.equals(first,second));
    true

    ReplyDelete