Monday, May 23, 2011

Beware of contains() method of List implementations


Target audience: Beginners

Every day, we deal with java.util.List that contains value objects. Some people might have misunderstood the outcome of contains() method of List implementation.

Just look at the bellow code example

public class ContainsEx {

public static void main(String[] args) {

// Creating a list of Person objects
List list = new ArrayList();
Person p1 = new Person("One");
list.add(p1);
Person p2 = new Person("Two");
list.add(p2);
Person p3 = new Person("Three");
list.add(p3);

// One more object similar to p1
Person oneMoreP1 = new Person("One");

// Check whether the list contains "One"
System.out.println(list.contains(oneMoreP1));
}
}

class Person {

private String name;

Person(String name) {
this.name = name;
}
}


If we run ContainsEx then we might think the output would be true. But wrong!!! the output will be


false


Why is that?

When a List contain objects, if we invoke contains(obj) method of that List, then the contains method actually iterates though all its objects and then one by one it checks whether that object is equal to the one which is passed through contains(obj) method. How does it check the quality is by invoking the equals(obj) method of Object. So you have to define how the object should be equal to another by defining (overriding) its equals() method. For example, if we want the two Person objects should be treated same if their names are equal then what we need to do is just override the equals() method of Person class in that manner. See the bellow code


class Person {

private String name;

Person(String name) {
this.name = name;
}

// This is not properly implemented.This is just for explanation
public boolean equals(Object obj) {
Person other = (Person) obj;
return name.equals(other.name);
}

}


Now we have overridden the equals() of the Person class. Two person objects will be treated as equal if both has same name.

If we run ContainsEx now, the results will be

true