开发者

Using java Collection<E>.contains(Object o) when overriding equals method

开发者 https://www.devze.com 2023-04-12 19:40 出处:网络
I have a List<Person> objects where person is defined like so public Person { private firstName; private lastName;

I have a List<Person> objects where person is defined like so

public Person {
    private firstName;
    private lastName;
    //getter and setter methods
    public boolean equals(Object obj) {
        return la开发者_Go百科stName.equals(obj.toString());
    }
}

Now I want to see if this List<Person> contains a certain last name.

if(myList.contains("Smith"))
    System.out.println("yay!");

However the way the contains method is specified is that is returns true when (o==null ? e==null : o.equals(e)). So in this instance it is using String.equals(Person) instead of Person.equals(String). Is there a simple way of fixing this or do I have to write my own logic for contains?


Is there a simple way of fixing this...

No, not using Collection.contains.

By the contract of equals the implementation must be symmetric:

for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.

This means that returning any thing else than false for somePerson.equals(someString) is a direct violation of the contract.

...or do I have to write my own logic for contains?

Yes. Use a for loop:

for (Person p : myList)
    if (p.getLastName().equals("Smith"))
        return true;
return false;

or, if you're using Java 8,

return myList.stream().anyMatch(p -> p.getLastName().equals("Smith"));


One way would be to construct a List<String> view using the existing myList and go ahead.

final List<Person> myList = yourList;
List<String> strView = new AbstractList<String>() { 
                    String get(int i) {
                             return myList.get(i).getLastName(); 
                       } 
                     int size() { return myList.size(); }
                  };

if(strView.contains("Smith")) System.out.println("Yaay");


You'll have to write your own logic for this.

I would strongly advise that when you override the equals method, you stick to the API defined by java Object#equals. The equals method is used in many places (hashmaps to name one), and using a different logic will get you into lots of trouble later on.


Since you're not looking for a Person the most communicative solution would be to have a method that specifically indicates it's looking for a last name, like containsLastName or whatever, or take an example Person and use it as a criteria-like object.


Another option here is to use Guava's Iterables.any

 Predicate<Person> findMe(final String name){
    return new Predicate<Person>(){
        public boolean apply(Person input){
            return input.lastname.equals(name);
        }
    }
 }

 boolean contains = Iterables.any(myList, findMe("Smith"));

Or

Function<Person, String> lastName = new Function<Person, String>(){
     public String apply(Person input){
        return input.lastName;
     }
}

boolean contains = Lists.transform(myList, lastName).contains("Smith");
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号