Core Java

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:

IntelliJ IDEA Plugins Repository

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:

IntelliJ IDEA 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:

IntelliJ IDEA toString template

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:

IntelliJ IDEA toString() template
 

Reference: IntelliJ IDEA: Generate equals, hashCode and toString with Google Guava from our JCG partner Michal Vrtiak at the vrtoonjava blog.

Michal Vrtiak

Michal is a freelancer currently located in Prague, Czech Republic with huge passion for Java platform. He is very enthusiastic about Dependency Injection, IntelliJ IDEA and loves to use both Spring and Java EE.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Jan
Jan
11 years ago

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.

Stuart Stephen
Stuart Stephen
11 years ago
Reply to  Jan

Beauty is in the eye of the BEER holder.

Yann Banan
11 years ago

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!!!

Ashish
Ashish
10 years ago
Reply to  Yann Banan

Of course, you have dropped the beer on the console already … ;)

Back to top button