Compact equals and hashcode - java

I have a bean with 4 attributes:
user
institutionId
groupId
postingDate
I use Eclipse to generate equals and hashcode but the resulting code is not pretty. Is there a compact way to do the same? Assuming I want equals & hashcode to use all the attributes or a subset of them.
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((groupId == null) ? 0 : groupId.hashCode());
result = prime * result + ((institutionId == null) ? 0 : institutionId.hashCode());
result = prime * result + ((postingDate == null) ? 0 : postingDate.hashCode());
result = prime * result + ((user == null) ? 0 : user.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;
ManGroupKey other = (ManGroupKey) obj;
if (groupId == null) {
if (other.groupId != null)
return false;
} else if (!groupId.equals(other.groupId))
return false;
if (institutionId == null) {
if (other.institutionId != null)
return false;
} else if (!institutionId.equals(other.institutionId))
return false;
if (postingDate == null) {
if (other.postingDate != null)
return false;
} else if (!postingDate.equals(other.postingDate))
return false;
if (user == null) {
if (other.user != null)
return false;
} else if (!user.equals(other.user))
return false;
return true;
}

In Java 7
public int hashCode() {
return Objects.hash(groupId, institutionId, postingDate, user);
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
// cast to correct class
Target o = (Target)obj;
return Objects.equals(groupId, o.groupId) &&
Objects.equals(institutionId, o.institutionId) &&
Objects.equals(postingDate, o.postingDate) &&
Objects.equals(user, o.user);
}

You could compact the code down, but the odds are far higher that you would introduce bugs than that you would do anything useful. All the parts of the equals and hash code method are there for a reason.
If it's bothering you most IDEs have a folding editor, just click the little yellow box (usually) and all the contents of the method get hidden away.

Instead of using the eclipse generated code, you can use Apache-common-langs(http://commons.apache.org/proper/commons-lang/) class HashCodeBuilder and EqualsBuilder to do this:
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this);
}

hashCode:
Either:
#Override
public int hashCode() {
return Objects.hash(user, institutionId, groupId, postingDate);
}
Or:
#Override
public int hashCode() {
int result = 17;
result = 31 * result + Objects.hashCode(user);
result = 31 * result + Objects.hashCode(institutionId);
result = 31 * result + Objects.hashCode(groupId);
result = 31 * result + Objects.hashCode(postingDate);
return result;
}
Equals:
public boolean equals(Object obj){
if (obj == this){
return true;
}
if (! (obj instanceof ManGroupKey)){
return false;
}
ManGroupKey other = (ManGroupKey) obj;
return Objects.equals(user, other.user)
&& Objects.equals(institutionId, other.institutionId)
&& Objects.equals(groupId, other.groupId)
&& Objects.equals(postingDate, other.postingDate);
}

You can at least remove one level of nesting by removing the other.x != null check.
Comparing a value in this way: x.equals(y) will always return false when y is null.
Aside from that: the .equals() method is a good example where a bit of reflection can be handy, possible extracted out into a generic utility method. All you have to do is run through the different fields and see if they're equal in the two objects, that can be done in a few lines.
Obviously that is only feasible when you actually want to compare each field (or you'll have to add some additions to it which let you choose the fields).

I think the library, that can suite you is apache common. It provides EqualsBuilder and HashCodeBuilder classes, that do exactly what you are looking for.
Consider this question for details: Apache Commons equals/hashCode builder
Here are some code snippets:
public class Bean{
private String name;
private int length;
private List<Bean> children;
#Override
public int hashCode(){
return new HashCodeBuilder()
.append(name)
.append(length)
.append(children)
.toHashCode();
}
#Override
public boolean equals(final Object obj){
if(obj instanceof Bean){
final Bean other = (Bean) obj;
return new EqualsBuilder()
.append(name, other.name)
.append(length, other.length)
.append(children, other.children)
.isEquals();
} else{
return false;
}
}
}

Related

How do I use overridden HashCode and Equals on my list?

This is probably a trivial question but I'm having some problems (Probably due to my lack of knowledge and experience and I can't seem to find example code anywhere as I'm not too sure what to search for).
I have a list of Custom objects, List<StackTrace>. I want to remove all duplicate objects from this list based only on two properties firstLineOfStackTrace and typeOfException.
I asked a similar question the other day and someone mentioned about overriding equals and hashCode. I did a bit of research and I think I have done that now.
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((firstLineOfStackTrace == null) ? 0 : firstLineOfStackTrace.hashCode());
result = prime * result + ((typeOfexception == null) ? 0 : typeOfexception.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;
LogEntry other = (LogEntry) obj;
if (firstLineOfStackTrace == null) {
if (other.firstLineOfStackTrace != null)
return false;
} else if (!firstLineOfStackTrace.equals(other.firstLineOfStackTrace))
return false;
if (typeOfexception == null) {
if (other.typeOfexception != null)
return false;
} else if (!typeOfexception.equals(other.typeOfexception))
return false;
return true;
}
My question is how do I actually use these overridden methods in my code to give me an output which has no duplicates?

Why is retainAll not accurately computing the intersection of two sets?

I'm using Java 6. I can't figure out why "retainAll" is not correctly computing the intersection of two sets. I have
for (ProductDto dtoProd : dto.getProducts())
{
System.out.println("dtoProd:" + dtoProd.getId());
} // for
for (ProductDto princProd : principal.getProducts())
{
System.out.println("princProd:" + princProd.getId());
} // for
dto.getProducts().retainAll(principal.getProducts());
Despite the fact I observe through my System.out's that I have the same products in both sets, after, the last call, my "dto.getProducts()" is empty. This is the relevant object's id and hashcode methods, if that matters ....
#Override
public int hashCode()
{
return this.id != null ? this.id.hashCode() : 0;
}
#Override
public boolean equals(Object obj)
{
boolean ret = false;
if (obj instanceof ProductDto)
{
final ProductDto other = (ProductDto) obj;
ret = (this.id == other.getId() || (this.id != null && this.id.equals(other.getId())));
}
return ret;
}
and here is the System.out info
dtoProd:777
dtoProd:778
dtoProd:110074257z
princProd:777
princProd:777SB
princProd:110074257z
princProd:110074258z
princProd:110074259z
princProd:6161
princProd:778
What else do I need to do to compute the correct intersection?

Comparing Fractions with Bool

So Im having a problem with my equals class
public boolean equals(Object other) {
if (other.equals(this.numerator) && other.equals(this.denominator))
return true;
else
return false;
}
it gives me the result of 9/2 eq 9/2= false.
(Rest of my code for referees )
https://gist.github.com/anonymous/6604f427cc9d17391478
What am i doing wrong?
I edited the code but still and dealing with an error of boolean and int
public boolean equals(Object other) {
if (other.equals(this.numerator) == getNumerator() && other.equals(this.denominator)== getDenominator())
return true;
else
return false;
}
When implementing equals, before checking if the objects are equal you should consider the next scenarios:
The two are actually references to the same object
The other object is null
The other object is an instance of a different type
and when checking equality between the two objects you should consider the nullness of every field involved in the comparison too. In most IDEs equals can be generated automatically, in eclipse:
Alt + Shift + s --> Generate hashCode() and equals()
the next is generated by eclipse:
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
A other = (A) obj;
if (denominator == null) {
if (other.denominator != null)
return false;
} else if (!denominator.equals(other.denominator))
return false;
if (numerator == null) {
if (other.numerator != null)
return false;
} else if (!numerator.equals(other.numerator))
return false;
return true;
}
return
(other.numerator.equals(this.numerator)
&&
other.denominator.equals(this.denominator))
Of couse this doesn't consider that 1/2 == 2/4.

How do I change what it means for objects to be duplicate in a set?

I want to store a set of Edges:
class Edge {
int u;
int v;
char symbol;
}
The problem is that it's possible for two Edge objects to have the same u, v and symbol, but they can both be stored in a HashSet because they're not the same object even though I want them to be considered the same object. How can I store only one object that has a unique (u, v, symbol) in a Set?
You need to override the following two methods equals and hashcode.
public boolean equals(Object obj) {
if (obj == null) return false;
if (!(obj instanceof Edge)) return false;
// return true if they are the same, otherwise false
}
public int hashCode() {
// return an int that represents similarity
// Example: name.hashCode(), if they are the same with the same name
}
Depends on what kind of set you want to use; The below applies for HashSet for instance, but not for any subclass of SortedSet
By overriding equals() and hashCode():
class Edge {
int u;
int v;
char symbol;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + symbol;
result = prime * result + u;
result = prime * result + v;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Edge other = (Edge) obj;
return symbol == other.symbol && u == other.u && v == other.v;
}
}
You have to override equals(). Like this:
public boolean equals(Object obj) {
//do the comparison here; remember to cast obj to Edge
}

Java SortedMap implemented with List of values

I want to have a Sorted map as follows:
srcAddr, dstAddr, srcPort, dstPort, protocol as keys
and a List of values as
packetLength, timeArrival for each key.
Is it possible to implement them in separate classes? I am confused if it will work this way.
Update:
I am getting an error indicating im not overriding abstract method compareTo(). Can you help me with it?
package myclassifier;
import java.io.Serializable;
import java.util.*;
public class Flows implements Serializable, Comparable {
String srcAddr, dstAddr, srcPort, dstPort, protocol;
public int compareTo(Flows other) {
int res = this.srcAddr.compareTo(other.srcAddr);
if (res != 0) {
return res;
}
res = this.dstAddr.compareTo(other.dstAddr);
if (res != 0) {
return res;
}
res = this.srcPort.compareTo(other.srcPort);
if (res != 0) {
return res;
}
res = this.dstPort.compareTo(other.dstPort);
if (res != 0) {
return res;
}
return this.protocol.compareTo(other.protocol);
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((dstAddr == null) ? 0 : dstAddr.hashCode());
result = prime * result + ((dstPort == null) ? 0 : dstPort.hashCode());
result = prime * result + ((srcAddr == null) ? 0 : srcAddr.hashCode());
result = prime * result + ((srcPort == null) ? 0 : srcPort.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;
Flows other = (Flows) obj;
if (dstAddr == null) {
if (other.dstAddr != null)
return false;
} else if (!dstAddr.equals(other.dstAddr))
return false;
if (dstPort == null) {
if (other.dstPort != null)
return false;
} else if (!dstPort.equals(other.dstPort))
return false;
if (srcAddr == null) {
if (other.srcAddr != null)
return false;
} else if (!srcAddr.equals(other.srcAddr))
return false;
if (srcPort == null) {
if (other.srcPort != null)
return false;
} else if (!srcPort.equals(other.srcPort))
return false;
return true;
}
}
You can write a, say a 'MyKey' class with srcAddr, dstAddr, srcPort, dstPort and protocol as member variables of it. You have to carefully override the equals and hashCode method of this class. Also this class has to implement the Comparable interface to indicate how your ordering will be determined based on member fields.
You can implement a class MyValue to have packetLength, timeArrival etc as members. This will be the value you want to store in your map.
Use TreeMap to store MyValue against MyKey.
you can implement different classes one for the key
public class Packet implements Serializable, Comparable {
String srcAddr, dstAddr, srcPort, dstPort;
public int compareTo(Object arg0) {
// your sorting logic here
return ...;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((dstAddr == null) ? 0 : dstAddr.hashCode());
result = prime * result + ((dstPort == null) ? 0 : dstPort.hashCode());
result = prime * result + ((srcAddr == null) ? 0 : srcAddr.hashCode());
result = prime * result + ((srcPort == null) ? 0 : srcPort.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;
Packet other = (Packet) obj;
if (dstAddr == null) {
if (other.dstAddr != null)
return false;
} else if (!dstAddr.equals(other.dstAddr))
return false;
if (dstPort == null) {
if (other.dstPort != null)
return false;
} else if (!dstPort.equals(other.dstPort))
return false;
if (srcAddr == null) {
if (other.srcAddr != null)
return false;
} else if (!srcAddr.equals(other.srcAddr))
return false;
if (srcPort == null) {
if (other.srcPort != null)
return false;
} else if (!srcPort.equals(other.srcPort))
return false;
return true;
}
}
And one for the data
public class Payload {
Integer packetLength;
Date timeArrival;
}
then when you put payload with a certain key in a sorted map it will be placed in order according to the compareTo method
You want sort your map based on its keys or values? Do you want the keys to be sorted alphabetically or in the order you've specified above? Overall it shouldn't be too difficult:
SorterMap<String, List> mySortedMap = new TreeMap<String, List>(myComparator);
mySortedMap.put("srcAddr", Arrays.asList(new Object[] {packetLengthValue, arrivalTimeValue}))
Where you should implement myComparator to sort the keys according to your requirements.

Categories

Resources