Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Contains for List of Pair

  List<Pair<String, String> > lp = new ArrayList<Pair<String, String> >();
  lp.add(new Pair("1", "2"));

How should I check if the list lp contains 1 and 2 i.e the Pair ("1", "2").

like image 765
kal Avatar asked Feb 10 '11 01:02

kal


People also ask

Can we use contains in list?

The contains() method of List interface in Java is used for checking if the specified element exists in the given list or not. Parameters: This method accepts a single parameter obj whose presence in this list is to be tested.


2 Answers

Your Pair class needs to implement equals() and hashCode() and you're all set. List.contains() is implemented in terms of the type's equals() method. See the API for List.contains(). (Edited a bit to address comments from @maaartinus, whose answer you should read b/c the observations are solid, and it's a bit ridiculous for me to fold them in here. As maaartinus points out, a best-practice here would be to avoid error-prone manual definitions for equals and hashcode, and instead build on Guava's helper functions for nullable equals and hashCode for n objects).

final class Pair<T> {

   final T left;
   final T right;

   public Pair(T left, T right)
   {
     if (left == null || right == null) { 
       throw new IllegalArgumentException("left and right must be non-null!");
     }
     this.left = left;
     this.right = right;
   }

   public boolean equals(Object o)
   {
     // see @maaartinus answer
     if (! (o instanceof Pair)) { return false; }
     Pair p = (Pair)o;
     return left.equals(p.left) && right.equals(p.right);
   } 

   public int hashCode()
   {
      return 7 * left.hashCode() + 13 * right.hashCode();
   } 
}

With suitable equals(), you can now do:

  lp.add(new Pair("1", "2"));
  assert lp.contains(new Pair("1","2"));

Responding to the comments below, perhaps it would be good to include a good reference for "Why do I need to implement hashCode()?"

  • JavaPractices.com — Implementing equals() — "if you override equals, you must override hashCode"

  • Object.equals() contract as defined in the API documentation

  • StackOverflow answer

like image 95
andersoj Avatar answered Sep 22 '22 23:09

andersoj


The implementation in the answer by andersoj

 return left != null && right != null && left.equals(p.left) && right.equals(p.right);

is wrong: The null tests clearly suggest that null is a legal value for left and right. So there are at least two problems there:

  • new Pair(null, null).hashCode() throws NPE
  • new Pair(null, null) does NOT equal to itself!

Have a look at Guava class Objects for a correct implementation. Use it or write a static helper methods like

public static boolean equal(Object a, Object b) {
    return a==b || a!=null && a.equals(b);
}
public static int hashCode(Object a) {
    return a==null ? 0 : a.hashCode();
}

and always use them.

Never ever write equals containing a null test.

It's to easy to blow it, and nobody noticed it. Using the Helper, it's trivial to get it right:

public boolean equals(Object o)  {
    if (!(o instanceof Pair)) return false;
    Pair p = (Pair) o;
    return Helper.equals(left, p.left) && Helper.equals(right, p.right);
} 

public int hashCode() {
    return 7 * Helper.hashCode(left) + 13 * Helper.hashCode(right);
} 

Of course, forbidding nulls in the constructor is an option, too.

like image 26
maaartinus Avatar answered Sep 20 '22 23:09

maaartinus