简体   繁体   中英

How to test for equality of Lists of String arrays

I think I can't see the forest for the trees... How do I test for equality (not identity) of all elements recursively in a List of String arrays? Here's a minimal example:

List<String[]> left = new ArrayList<>();
left.add(new String[]{"one", "two"});

List<String[]> right = new ArrayList<>();
right.add(new String[]{"one", "two"});

System.out.println(left.equals(right) ? "Yeah!" : "This is not what I want.");

I want to use this in unit tests.

A bit more context: I have a class that holds several fields, some of which are List of String arrays and some are Set s of String arrays. The class is a result of a parser (actually an intermediate step in a cascade of parsers). In order to test the parser I want to check for equality of instances of the class in question. The IDE-autogenerated equals implementation uses a cascade of Objects.equals invocations on the several List<String[]> and Set<String[]> fields, which is---so I figured---equivalent to the minimal example that I've provided above.

Test that both lists have the same size. Then if they do, iterate on each of them, and compare each pair of arrays using Arrays.equals() .

It would be easier if you had a List of lists instead ( List<List<String>> ), because lists can be compared using equals() directly.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.swing.text.html.HTMLDocument.Iterator;


public class test 
{
  public static void main(String args[])
  {

      List<String[]> left = new ArrayList<String[]>();
      left.add(new String[]{"one", "two"});

      List<String[]> right = new ArrayList<String[]>();
      right.add(new String[]{"one", "two"});

      java.util.Iterator<String[]> leftIterator =left.iterator();
      java.util.Iterator<String[]> rightIterator =right.iterator();
      if(left.size() !=right.size())   System.out.println("not equal");
      for(;leftIterator.hasNext();)
      {
         if(Arrays.equals(leftIterator.next(), rightIterator.next())) continue;
         else
         {
             System.out.print("not equal");
             break;
         }
      }


  }
}

You want to compare each list, keep track of if they are equal using a boolean. I'm not aware of a single function that will do this directly for you.

    List<String[]> left = new ArrayList<>();
    left.add(new String[]{"one", "two"});

    List<String[]> right = new ArrayList<>();
    right.add(new String[]{"one", "two"});

    boolean isEqual = true;
    if (left.size() == right.size())
    {
        // Test for equality
        for (int i = 0; i < left.size(); i++)
        {
            // Compare each array in the list
            if (!Arrays.equals(leftArray, rightArray))
            {
                isEqual = false;
                break;
            }
        }
    }
    else
    {
        // The two list are not even the same length, so are not equal.
        isEqual = false;
    }

    System.out.println(isEqual ? "Yeah!" : "This is not what I want.");

Thanks to everyone for your input. This is my resulting code.

protected static boolean equalsCollectionOfArrays(Collection<? extends Object[]> leftCollection,
                                                   Collection<? extends Object[]> rightCollection) {
    if (leftCollection.size() != rightCollection.size()) {
        return false;
    } else {
        Iterator<? extends Object[]> left = leftCollection.iterator();
        Iterator<? extends Object[]> right = rightCollection.iterator();
        while (left.hasNext()) {
            if (!Arrays.equals(left.next(), right.next())) {
                return false;
            }
        }
        return true;
    }
}

protected static int hashCodeCollectionOfArrays(Collection<? extends Object[]> collection) {
    int hash = 3;
    for (Object[] objects : collection) {
        hash = 67 * hash + Arrays.hashCode(objects);
    }
    return hash;
}

It turned out that my problem was not limited to List<String[]> , but that I ran into the same issues with Set<String[]> and also hashCode() . I've ended up with these two methods that I've incorporated into the class' equals and hashCode implementation. The generic wildcard is not necessary (there are only String arrays), but I just wanted to check out my understanding of generics by the way when I am learning a basic lesson.

I am considering to avoid arrays in the future. Any comments are very welcome.

If you need to compare lists, try using equals() of that particular list instance providing another one to compare to.

If you need to compare arrays, try using Arrays.equals() .

If you are doing this in test methods org.junit.Assert 's assertArrayEquals() or assertEquals() should od as they will call those methods behind the covers.

The Java documentation requires list equals() to behave as you're using it, so your code would work if these were List s of Lists :

boolean equals(Object o)

Compares the specified object with this list for equality. Returns true if and only if the specified object is also a list, both lists have the same size, and all corresponding pairs of elements in the two lists are equal. (Two elements e1 and e2 are equal if (e1==null ? e2==null : e1.equals(e2)).) In other words, two lists are defined to be equal if they contain the same elements in the same order. This definition ensures that the equals method works properly across different implementations of the List interface.

However at the "leaves" you have plain Java arrays. These will use the Object definition of equals , which tests for reference identity, not value equality.

One way around this in your tests is to write a little helper factory routine that accepts a variable argument list of String s and produces List returns to replace the Java arrays you're currently using. Then all ought to work fine. Your example would look like this:

// A little helper to avoid the awkward syntax
// Arrays.asList(new String [] { "one", "two" })
public static List<String> listOf(String ... strings) {
    return Arrays.asList(strings);
}

public static void main(String[] args) {
    List<List<String>> left = new ArrayList<>();
    left.add(listOf("one", "two"));

    List<List<String>> right = new ArrayList<>();
    right.add(listOf("one", "two"));

    System.out.println(left.equals(right) ? "Yeah!" : "This is not what I want.");
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM