The problem
The reason why your approach did not work is because the List#contains
(documentation) method uses the result of Person#equals
to decide if an element from the list is the same as the argument. If you have not implemented this method than it searches the method in the inheritance tree of Person
. As every object inherits from the class Object
you will fall back to Object#equals
(documentation) if no class on the way to Object
has implemented equals
. However this Object#equals
method compairs objects by their identity (place in the memory). That means that if you create an object that has the same properties (like name and so on) it just will be a copy but not the same as the one in the list, per identity.
Note that there are many questions here at StackOverflow for this topic. If you're not familiar with it you should check it out. Here is an example explaining it in more detail: What issues should be considered when overriding equals and hashCode in Java?
There are multiple ways of solving this problem.
Let's first consider a very straightforward and easy way.
Iterating manually
We manually iterate the list and check every entry regarding the relevant parameters.
public Person lookupPerson(String personName) {
for (final Person person : persons) {
// Access properties of person, usage of getter methods would be good
if (person.name.equals(personName)) {
// Found matching person
return person;
}
}
// Traversed whole list but did not find a matching person
return null;
}
(like seen in the answer of @DeepakS)
Implement equals and hashCode, use indexOf
Now we let the list do the iterating and matching part by using List#indexOf
(documentation). This approach is similar to yours with contains
(documentation) but we would also like to get the element, not just check if its there or not.
public class Person {
...
@Override
public boolean equals(final Object o) {
if (o == null) {
return false;
}
if (!(o instanceof Person)) {
return false;
}
if (o == this) {
return true;
}
final Person other = (Person) o;
return other.name.equals(this.name);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result;
if (this.name != null) {
result += this.name.hashCode();
}
return result;
}
}
And the lookup method:
public Person lookupPerson(String personName) {
// The needle to search for
final Person needle = new Person(personName);
// The needle will now be equals to list objects
// regarding its equals method which only checks
// for the name
final int index = persons.indexOf(needle);
if (index != -1) {
// Get the element at this position
return persons.get(index);
} else {
return null;
}
}
(like seen in the answer of @AxelH)
Compact Java 8 solution
If you have Java 8 you may prefer a very compact variant. Therefore we use Stream#filter
(documentation) which filters elements of a stream based on if the method returns true
or false
(a so called Predicate
(documentation)). So we just need to implement a check for the name there and are finished.
public Person lookupPerson(String personName) {
return list.stream()
.filter(p -> p.name.equals(personName))
.findAny();
}
(like seen in the answer of @GaneshToni)