5

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; } 
8
  • What do you mean, "compact way"? It depends on what your requirements for equals is. If you don't need it all, delete some. IIRC there are some reflective ones as well, alternate generators, and ways to choose which fields are used. Commented Mar 14, 2014 at 16:39
  • Sonar reports a lot of "If Stmts Must Use Braces" warnings. Hashcode is fine, equals is very difficult to read. Commented Mar 14, 2014 at 16:39
  • @LluisMartinez Reformat it. Commented Mar 14, 2014 at 16:40
  • 2
    Take a look at Objects.equals and Objects.hash in java.util for Java >= 7, otherwise google guava has those helpers. Commented Mar 14, 2014 at 16:40
  • I'm stuck with Java 5 and can't use Guava, but that's the way I'd like. Commented Mar 14, 2014 at 16:42

6 Answers 6

6

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); } 
Sign up to request clarification or add additional context in comments.

1 Comment

You need to cast obj in the equals method.
5

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.

Comments

4

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); } 

2 Comments

Although there are some possible drawbacks: 1. reflection is slower, 2. the order is not really under your control, 3. all fields are used (which might or might not be what you want)
I pick this one because: a) I can't use Java 7 (or Guava) b) performance is not an issue (not thousands of objects) and c) in this case I use all fields.
2

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); } 

1 Comment

return Objects.equals(user, other.user). I cannot edit myself, since 6 characters must be changed, "user " got just four :)
1

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).

2 Comments

But then you won't return true if both self and other have x as null.
@TimB: if you invert the checks and instead use if(this.postingDate != null) { if(!(this.postingData.equals(other.postingData))} then this should not be a problem, right? Just return false for every intermediate check and return true at the very end as fallback.
1

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; } } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.