IntelliJ IDEA: Generate equals, hashCode and toString with Google Guava
THE PROBLEM
In the world of Java, we’re quite often in the need of writing equals, hashCode and toString methods. To be honest, this is usually only an boilerplate obligation.
Thanks to smart IDEs, we don’t usually do this by ourselves anymore. We just let and IDE to do the hard work. There is one problem though. The generated code is usually incredibly ugly. Let’s consider following POJO:
public class Beer { private String brand; private String type; private int degrees; private double alcoholPercentage; private List<String> ingredients; // constructor // getters, setters if needed }
THE USUAL SOLUTION
All of the major IDEs have the ability of generating the methods I mentioned, but this is how hashCode, equals and toString would look like:
1. equals – long list of IF statements …
@Override public boolean equals(final Object o) { if (this == o) { return true; } if (!(o instanceof Beer)) { return false; } final Beer beer = (Beer) o; if (Double.compare(beer.alcoholPercentage, alcoholPercentage) != 0) { return false; } if (degrees != beer.degrees) { return false; } if (!brand.equals(beer.brand)) { return false; } if (!ingredients.equals(beer.ingredients)) { return false; } if (!type.equals(beer.type)) { return false; } return true; }
2. hashCode – confusing magic numbers, xors and shifts
@Override public int hashCode() { int result; long temp; result = brand.hashCode(); result = 31 * result + type.hashCode(); result = 31 * result + degrees; temp = alcoholPercentage != +0.0d ? Double.doubleToLongBits(alcoholPercentage) : 0L; result = 31 * result + (int) (temp ^ (temp >>> 32)); result = 31 * result + ingredients.hashCode(); return result; }
3. toString – nasty string concatenation
@Override public String toString() { return 'Beer{' + 'brand='' + brand + '\'' + ', type='' + type + '\'' + ', degrees=' + degrees + ', alcoholPercentage=' + alcoholPercentage + ', ingredients=' + ingredients + '}'; }
SOLUTION WITH GOOGLE GUAVA
Maybe you’ve heard of Google Guava. Maybe you’re already using it. Anyway, Google Guava is a nice little library that provides lot of goodies for Java. Using Guava we can rewrite three methods above to better looking alternatives:
1. equals – army of IF statements transformed to chained call
@Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } final Beer other = (Beer) obj; return Objects.equal(this.brand, other.brand) && Objects .equal(this.type, other.type) && Objects .equal(this.degrees, other.degrees) && Objects .equal(this.alcoholPercentage, other.alcoholPercentage) && Objects .equal(this.ingredients, other.ingredients); }
2. hashCode – one-liner
@Override public int hashCode() { return Objects.hashCode(brand, type, degrees, alcoholPercentage, ingredients); }
3. toString – consistent chained call
@Override public String toString() { return Objects.toStringHelper(this) .add('brand', brand) .add('type', type) .add('degrees', degrees) .add('alcoholPercentage', alcoholPercentage) .add('ingredients', ingredients) .toString(); }
SETUP YOUR INTELLIJ IDEA
For the equals and hashCode, there is a plugin called Equals and HashCode Deluxe Generator from Michal Jedynak. You can install it directly within IntelliJ, just type CTRL + SHIFT + A (or CMD + SHIFT + A on Mac) and type Browser repositories. That should bring you to following dialog where you can search for the plugin:
Using the new equals and hashCode plugins is simple, you will have new context menu option equals() and hashCode() deluxe directly next to the old one. Just press ALT+INS (or CTRL+N on Mac) and you will see familiar generate menu:
As far as toString is concerned, we only have to create a new template in IntelliJ. Press ALT + INS and go to toString() menu option. Click on the Settings button and navigate to Templates tab. In the Templates tab click the + button:
Give to the new template a name (like Guava toString or so) and paste the following code into the editor:
public String toString() { #set ($autoImportPackages = 'com.google.common.base.Objects') return Objects.toStringHelper(this) #foreach ($member in $members) .add('$member.name', $member.accessor) #end .toString(); }
Using new template is easy, just enter generate menu (ALT + INS), select toString() and be sure to pick the right template:
Reference: IntelliJ IDEA: Generate equals, hashCode and toString with Google Guava from our JCG partner Michal Vrtiak at the vrtoonjava blog.
Put 10 developers in a room and there will be 10 views on how code should formatted, what looks pretty and what looks ugly. Beauty is in the eye of the beholder. This looks like (some) effort for no value add.
Beauty is in the eye of the BEER holder.
Nice IntelliJ template. Thank you!
Note that your hashcode is built on mutable fields, wich means you can get undesirable things like:
Beer beer = new Beer(“Chimay”, “Trappiste”, 6, 8.0, Arrays.asList(“hop”, “water”));
Set beers = new HashSet();
beers.add(beer);
beer.setDegrees(10);
for (Beer birra : beers) {
System.out.println(birra); // Beer{brand=’Chimay’, type=’Trappiste’, etc.
}
System.out.println(beers.contains(beer)); // FALSE!!!
Of course, you have dropped the beer on the console already … ;)