Comparing objects within a set - java

Right now I have this Java code
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
public class Dummy {
private String value;
public Dummy(final String value) {
this.value = value;
}
public boolean equals(final Object that) {
return that instanceof Dummy && Objects.equals(value, ((Dummy) that).value);
}
public int hashcode() {
return Objects.hash(value);
}
public static void main(final String... args) {
final Set<Dummy> dummies = new HashSet<>();
dummies.add(new Dummy("toto"));
System.out.println(dummies.contains(new Dummy("toto")));
}
}
The output is "false", and I'm supposed to change it to "true" by changing only one character, but I have absolutely no idea how to do that... Any ideas? Thanks. :)

hashcode() is not a Object's method but hashCode() is.
public int hashcode() {
return Objects.hash(value);
}
should be
public int hashCode() {
return Objects.hash(value);
}

In my case I had lots of objects who all need a equals and hash method. I have used lombok to reduce the work and code.
#Data
#AllArgsConstructor
#EqualsAndHashCode
public class JsonPictureStuff {
private String type;
private String url;
private String width;
private String height;
}
The annotations instruct lombok to add the code for you.

your set is not working because you are implementing equals and hashcode in a not proper way...
specially because you are not even considering the string field
you are avoiding the annotation Override that will hint you about wrongly named methods like hashcode and hashCode
you can do something like
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((value == null) ? 0 : value.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Dummy other = (Dummy ) obj;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
in ide like eclipse you can do right click and auto generate those methods so you can save the implementation

Related

Comparing two instances of class having big number of attributes

I have a class having more than 30 attributes.
I want to override the equals method in order to compare two instance of my class.
However I want to avoid re-write all the 30 attributes in my method as this
#Override
public boolean equals(java.lang.Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Address address = (Address) o;
return Objects.equals(this.attr1, address.attr1) &&
Objects.equals(this.attr2, address.attr2) &&
Objects.equals(this.attr3, address.attr3) &&
......
Objects.equals(this.attr30, address.attr30);
}
Have you a more simple and proper way ?
Well, this is basically the type of boilerplate code that is necessary. Luckily, there are lots of developers just as annoyed of writing such code as you are. For reasons like that, Project Lombok was founded.
Please see this link.
As an example, see the following two code snippets extracted from the page that I linked above:
Lombok
import lombok.EqualsAndHashCode;
#EqualsAndHashCode(exclude={"id", "shape"})
public class EqualsAndHashCodeExample {
private transient int transientVar = 10;
private String name;
private double score;
private Shape shape = new Square(5, 10);
private String[] tags;
private int id;
public String getName() {
return this.name;
}
#EqualsAndHashCode(callSuper=true)
public static class Square extends Shape {
private final int width, height;
public Square(int width, int height) {
this.width = width;
this.height = height;
}
}
}
Vanilla Java
import java.util.Arrays;
public class EqualsAndHashCodeExample {
private transient int transientVar = 10;
private String name;
private double score;
private Shape shape = new Square(5, 10);
private String[] tags;
private int id;
public String getName() {
return this.name;
}
#Override public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof EqualsAndHashCodeExample)) return false;
EqualsAndHashCodeExample other = (EqualsAndHashCodeExample) o;
if (!other.canEqual((Object)this)) return false;
if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
if (Double.compare(this.score, other.score) != 0) return false;
if (!Arrays.deepEquals(this.tags, other.tags)) return false;
return true;
}
#Override public int hashCode() {
final int PRIME = 59;
int result = 1;
final long temp1 = Double.doubleToLongBits(this.score);
result = (result*PRIME) + (this.name == null ? 43 : this.name.hashCode());
result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));
result = (result*PRIME) + Arrays.deepHashCode(this.tags);
return result;
}
protected boolean canEqual(Object other) {
return other instanceof EqualsAndHashCodeExample;
}
public static class Square extends Shape {
private final int width, height;
public Square(int width, int height) {
this.width = width;
this.height = height;
}
#Override public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Square)) return false;
Square other = (Square) o;
if (!other.canEqual((Object)this)) return false;
if (!super.equals(o)) return false;
if (this.width != other.width) return false;
if (this.height != other.height) return false;
return true;
}
#Override public int hashCode() {
final int PRIME = 59;
int result = 1;
result = (result*PRIME) + super.hashCode();
result = (result*PRIME) + this.width;
result = (result*PRIME) + this.height;
return result;
}
protected boolean canEqual(Object other) {
return other instanceof Square;
}
}
}
If you like this approach, I'd recommend checking out Project Lombok in its entirety. It really helps cleaning up your code!
!!! Beware !!!
In order to be able to actually use methods generated by Lombok, you need to install the Lombok plugin into your IDE! Otherwise, your IDE won't know of the automatically generated methods.
You can use the Field class in the java.lang.reflect package like so:
#Override
public boolean equals(Object o) {
//instanceof check, null check, etc
Field[] fields = Address.class.getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true);
if (!field.get(this).equals(field.get((Address) o))) {
return false;
} //end if
} catch (IllegalAccessException e) {
//handle exception
} //end try catch
} //end for
return true;
} //equals
You have this method in apache commons library that uses reflection for compare them
org.apache.commons.lang.builder.EqualsBuilder.reflectionEquals(Object, Object)
Example
import org.apache.commons.lang.builder.EqualsBuilder;
public class MyObject {
...
#Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
}
You can use lombok project to auto-generate hashCode and equals methods at build time .
You can use Unitils http://www.unitils.org/cookbook.html
import static org.unitils.reflectionassert.ReflectionAssert.*;
// Exact field-by-field comparison
assertReflectionEquals(new Person("John", "Doe", new Address("New street", 5, "Brussels")),
new Person("John", "Doe", new Address("New street", 5, "Brussels"));

Using Objects as keys in Java HashMap

package test;
import java.util.HashMap;
public class test {
public static void main(String args[]) {
HashMap<ID, String> h = new HashMap<ID, String> ();
String b;
ID id1 = new ID(100);
ID id2 = new ID(200);
ID id3 = new ID(200);
h.put(id1, "apple");
h.put(id2, "pear");
**System.out.println(h.containsKey(id3));**
}
}
class ID {
Integer code;
public ID(Integer id) {
this.code = id;
}
#Override
public int hashCode()
{
return code.hashCode();
}
#Override
public boolean equals(Object o)
{
return this.code.equals(o);
}
}
the output of this program is "false". I can't understand of this result. I implemented hashCode and equals which are overrided. I don't have an idea how to solve. How to use objects as keys in java HashMap?
Your equals implementation is wrong :
public boolean equals(Object o)
{
return this.code.equals(o); // this will never return true,
// since you are comparing an Integer instance
// to an ID instance
}
You should compare this code to the other code:
public boolean equals(Object o)
{
if (!(o instanceof ID))
return false;
ID oid = (ID) o;
return this.code.equals(oid.code);
}
Wrong Implementation of equals method. According to your implementation it executes the Integer class equals method. We should handle the logic without execute library classes equals methods.
#Override
public boolean equals(Object o) {
if (o == null || ((o instanceof ID) && o.hashCode() != this.hashCode())) {
return false;
}
return true;
}

== vs. equals() references/pointers JAVA

I'm learning about == vs. equals() and doing various examples. For this one, I understand why r==s is false, but why is r.equals(s) false if they now both have the same content?
public class StringProgram{
public static void main(String[] args) {
Person r = new Person("A");
Person s = new Person("J");
s.setName("A");
System.out.println(r.getName());//A
System.out.println(s.getName());//A
System.out.println(r==s);//false
System.out.println(r.equals(s));//false
}
}
Here is the code of Person :
public class Person{
private String name;
public Person(String d){
name=d;
}
public void setName(String a){
name=a;
}
public String getName(){
return name;
}
}
EDIT: I see that I have to override it now, but I still don't understand how the assignment works in the example below. I just don't understand why t.getName() is Keen if t is assigned to u.
public class StringProgram{
public static void main(String[] args) {
Person t = new Person("Gene");
Person u = t;
u.setName("Keen");
System.out.println(t.getName());//Keen
System.out.println(t.equals(u));//true
}
}
All classes in java inherit from the Object class. When you do an r.equals(s), it uses the .equals() method as defined in Object class. To make it work as you desire, you need to define the .equals() method for the Person class by overriding the .equals() method.
Eg. Add this in your Person class:
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
Note: I used eclipse to generate the equals and hashcode method for me. You may read this thread to understand why hashcode() needs to be overridden.
equals() is just a method, there's nothing special about it. In particular, it doesn't automatically know how to compare the content of two objects.
The equals() method of class Object does the same thing as ==. If you do not override the equals() method in your class Person, then it's not automatically going to compare the content of Person objects.
You have to override the equals() method in class Person so that it does the comparison in the way you want.
public class Person {
private String name;
// ...
#Override
public boolean equals(Object o) {
if (!(o instanceof Person)) {
return false;
}
return ((Person) o).name.equals(this.name);
}
}
Java can't guess what you want to do, you have to tell it that two persons are the same if they have the same name. You must override equals :
#Override
public boolean equals(Object o) {
if (o == this) return true;
if (o == null) return false;
if (!(o instanceof Person)) return false;
Person that = (Person) o;
if (name == null && that.name == null) return true;
if (name == null || that.name == null) return false;
return that.name.equals(name);
}
All java classes inherits from Object, and to properly compare your class you should override the equals() method.
public Person(String d){
name=d;
}
public void setName(String a){
name=a;
}
public String getName(){
return name;
}
#Override
public boolean equals(Object obj) {
return obj instanceof Person &&
this.getName().equals(((Person)obj).getName());
}

hashCode(), equals(Object) and compareTo(Class)

I've following the following Vertex class and it implements equals, hashCode and compareTo method. Even then my HashMap returns null. I don't know why?
public class Vertex implements Comparable<Vertex> {
int id;
public Vertex(int number) {
id = number;
}
public boolean equals(Object other) {
if (other == null)
return false;
else if (other.getClass() != this.getClass())
return false;
else {
Vertex copy = (Vertex) other;
if (copy.id == this.id)
return true;
else
return false;
}
}
public int hasCode() {
int prime = 31;
int smallPrime = 3;
int hashCode = this.id ^ smallPrime - prime * this.hasCode();
return hashCode;
}
public int compareTo(Vertex other) {
if (this.id < other.id)
return -1;
else if (this.id > other.id)
return 1;
else
return 0;
}
}
Your method is called hasCode(). Make it hashCode() instead.
I'd suggest using your IDE to automatically generate hashCode() and equals(..). That will generate the proper methods (right now you have a recursive call in hashCode())
Also, in your equals() method
else if(other.getClass()!=this.getClass())
return false;
can be changed to
else if(!(other instanceof Vertex))
return false;
Try this based on what Integer does. Note: the use of #Override would have shown you were overriding the wrong method.
public class Vertex {
final int id;
public Vertex(int number){
id = number;
}
#Override
public boolean equals(Object other){
if(!(other instanceof Vertex)) return false;
return ((Vertex)other).id == id;
}
#Override
public int hashCode() { return id; }
}

how to insert into set without changing the equals and hashcode

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.
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 Persons for you.
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
}
});
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;
}
}
}

Categories