I'm looking for a suggestion.
I have a Person
class with String firstName and String lastName
When i'm tying to insert the list values with the same String like :
set.add(new Person("firstName","lastName"))
set.add(new Person("firstName","lastName"))
The set doesn`t filter the objects and they still getting in the set.
There is any suggestion to create set list without overriding the equales and hashcode functions?
Maybe with guava or some groovy list?
Thanks,
Or.
You can create a TreeSet with your own Comparator.
Set<Person> set = new TreeSet<Person>(new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
// Your own compare logic
}
});
In Guava there's an Equivalence class designed to such things. Create your own Equivalence
class like this one:
import com.google.common.base.Equivalence;
import com.google.common.base.Objects;
public class PersonEquivalence extends Equivalence<Person> {
@Override
protected boolean doEquivalent(Person p1, Person p2) {
return Objects.equal(p1.getFistName(), p2.getFistName())
&& Objects.equal(p1.getLastName(), p2.getLastName());
}
@Override
protected int doHash(Person person) {
return Objects.hashCode(person.getFistName(), person.getLastName());
}
}
And then this code
Set<Equivalence.Wrapper<Person>> set = Sets.newHashSet();
PersonEquivalence personEquivalence = new PersonEquivalence();
set.add(personEquivalence.wrap(new Person("Joe", "Doe")));
set.add(personEquivalence.wrap(new Person("Joe", "Doe")));
set.add(personEquivalence.wrap(new Person("Jane", "Doe")));
System.out.println(set);
prints
[PersonEquivalence@8813f2.wrap(Person{firstName=Jane, lastName=Doe}),
PersonEquivalence@8813f2.wrap(Person{firstName=Joe, lastName=Doe})]
Of course it's a bit verbose, but you can create ForwardingSet to automatically wrap and unwrap Person
s for you.
You can't, without violating the contract of Set
. Either don't use a Set
, or wrap the Person
in another class that implements equals
and hashcode
based on the inner Person
(see the other answer for a way to do this in Guava).
Here's a rough attempt at my map suggestion.
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class PeopleCarrier implements Iterable<Person>{
private Map<PersonKey, Person> storage = new HashMap<PersonKey, Person>();
public void add(Person p) {
PersonKey pk = new PersonKey(p);
storage.put(pk, p);
}
public boolean contains(Person p) {
return storage.containsKey(new PersonKey(p));
}
@Override
public Iterator<Person> iterator() {
return new Iterator<Person>() {
private Iterator<PersonKey> i = storage.keySet().iterator();
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public Person next() {
return storage.get(i.next());
}
@Override
public boolean hasNext() {
return i.hasNext();
}
};
}
private class PersonKey {
private String firstname;
private String lastname;
public PersonKey(Person p) {
this.firstname = p.getFirstname();
this.lastname = p.getLastname();
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result
+ ((firstname == null) ? 0 : firstname.hashCode());
result = prime * result
+ ((lastname == null) ? 0 : lastname.hashCode());
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof PersonKey))
return false;
PersonKey other = (PersonKey) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (firstname == null) {
if (other.firstname != null)
return false;
} else if (!firstname.equals(other.firstname))
return false;
if (lastname == null) {
if (other.lastname != null)
return false;
} else if (!lastname.equals(other.lastname))
return false;
return true;
}
private PeopleCarrier getOuterType() {
return PeopleCarrier.this;
}
}
}