Category Archives: Guava

IntelliJ IDEA 14.1: Better equals(), hashCode() and toString()

PROBLEM

Let’s assume we want to create the default equals(), hashCode() and toString() with the following bean:-

public final class Person {
    private final String name;
    private final Collection<Car> cars;

    public Person(final String name, final Collection<Car> cars) {
        this.name = name;
        this.cars = cars;
    }

    public String getName() {
        return name;
    }

    public Collection<Car> getCars() {
        return cars;
    }
}

Most IDEs, including older version of IntelliJ, have code generation features that would create something similar to this:-

public final class Person {
    ...

    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        final Person person = (Person) o;

        if (name != null ? !name.equals(person.name) : person.name != null) {
            return false;
        }
        return !(cars != null ? !cars.equals(person.cars) : person.cars != null);
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + (cars != null ? cars.hashCode() : 0);
        return result;
    }

    @Override
    public String toString() {
        return "Person{" +
               "name='" + name + '\'' +
               ", cars=" + cars +
               '}';
    }
}

While it works, the generated code is usually crazy horrendous.

SOLUTION

With IntelliJ 14.x, it allows us to select templates from several proven libraries.

To generate equals() and hashCode(), select equals() and hashCode() option from the Generate pop-up dialog:-

There are several templates to choose from:-

Here’s an example of equals() and hashCode() using Guava and getter methods:-

public final class Person {
    ...

    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        final Person person = (Person) o;
        return Objects.equal(getName(), person.getName()) &&
               Objects.equal(getCars(), person.getCars());
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(getName(), getCars());
    }
}

To generate toString(), select toString() option from the Generate pop-up dialog:-

Again, there are several templates to choose from:-

Here’s an example of toString() using Guava:-

public final class Person {
    ...

    @Override
    public String toString() {
        return Objects.toStringHelper(this)
                .add("name", name)
                .add("cars", cars)
                .toString();
    }
}

Guava: Testing equals(..) and hashcode(..)

PROBLEM

Let’s assume we want to test the following equals(..):-

public class Person {
    private String name;
    private int age;

    @Override
    public boolean equals(Object o) {
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        Person person = (Person) o;
        return Objects.equal(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(name);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

A correctly implemented equals(..) must be reflexive, symmetric, transitive, consistent and handles null comparison.

In another word, you have to write test cases to pass at least these 5 rules. Anything less is pure bullshit.

SOLUTION

You can write these tests yourself… or you can leverage Guava’s EqualsTester. This library will test these 5 rules and ensure the generated hashcode matches too.

First, include the needed dependency:-

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava-testlib</artifactId>
    <version>18.0</version>
    <scope>test</scope>
</dependency>

Instead of writing JUnit tests, I’ll be writing Spock specs, which is essentially built on top of Groovy, because it allows me to write very clear and clean tests.

class PersonSpec extends Specification {

    def person = new Person(name: 'Mike', age: 10)

    def "equals - equal"() {
        when:
        new EqualsTester().
                addEqualityGroup(person,
                                 new Person(name: 'Mike', age: 10),
                                 new Person(name: 'Mike', age: 20)).
                testEquals()

        then:
        notThrown(AssertionFailedError.class)
    }

    def "equals - not equal"() {
        when:
        new EqualsTester().
                addEqualityGroup(person,
                                 new Person(name: 'Kurt', age: 10)).
                testEquals()

        then:
        thrown(AssertionFailedError.class)
    }
}

Oh… wait for it… BOOM!

Guava: Reducing Cyclomatic Complexity with Objects.firstNonNull(…)

PROBLEM

Ever written code like this?

Employee employee = employeeService.getByName(employeeName);

if (employee == null) {
    employee = new Employee();
}

While it works, it has several minor problems:-

  • The above code has cyclomatic complexity of 2 due to the if logic.
  • We cannot define final on employee object.
  • Too many lines of code, and seriously, it looks very 2003.

SOLUTION

Guava provides a much cleaner solution to address these problems:-

final Employee employee = Objects.firstNonNull(employeeService.getByName(employeeName),
                                               new Employee());

Guava: FluentIterable vs Collections2

PROBLEM

Guava’s Collections2 is great when dealing with collections, but it quickly becomes rather clumsy and messy when we try to combine multiple actions together.

For example, say we have userIds, which is a collection of user IDs. For each user ID, we want to retrieve the Employee object and add it into an immutable set if the lookup is successful. So, we essentially want to perform a “tranform” and “filter” here.

By using strictly Collections2, we ended up with the following code:-

final ImmutableSet<Employee> employees = ImmutableSet.copyOf(
        Collections2.filter(
                Collections2.transform(userIds,
                                       new Function<String, Employee>() {
                                           @Override
                                           public Employee apply(String userId) {
                                               return employeeService.getEmployee(userId);
                                           }
                                       }),
                new Predicate<Employee>() {
                    @Override
                    public boolean apply(Employee employee) {
                        return employee != null;
                    }
                }));

While it works, it may be confusing to those reading the code due to the nested functions.

SOLUTION

A better approach is to use FluentIterable that allows us to write more natural top-to-bottom code:-

final ImmutableSet<Employee> employees = FluentIterable
        .from(userIds)
        .transform(new Function<String, Employee>() {
            @Override
            public Employee apply(String userId) {
                return employeeService.getEmployee(userId);
            }
        })
        .filter(new Predicate<Employee>() {
            @Override
            public boolean apply(Employee employee) {
                return employee != null;
            }
        })
        .toImmutableSet();

Guava: Elegant Caching Mechanisms

There are many different ways to implement a caching mechanism. Google’s Guava provides very simple and elegant solutions to do so.

OPTION 1: Caching using Supplier

If you want to cache just one thing, Supplier should satisfy that requirement.

private Supplier<Collection<Person>> allEmployeesCache = Suppliers.memoizeWithExpiration(
        new Supplier<Collection<Person>>() {
            public Collection<Person> get() {
                return makeExpensiveCallToGetAllEmployees();
            }
        }, 1, TimeUnit.DAYS);

public Collection<Person> getAllEmployees() {
    return allEmployeesCache.get();
}

In the above example, we cache all employees for a day.

OPTION 2: Caching using LoadingCache

If you want to cache multiple things (ex: think Hashmap-like), LoadingCache should satisfy that requirement.

private LoadingCache<String, Collection<Person>> employeeRoleLoadingCache = CacheBuilder.newBuilder()
        .expireAfterWrite(1, TimeUnit.DAYS)
        .maximumSize(1000)
        .build(new CacheLoader<String, Collection<Person>>() {
            @Override
            public Collection<Person> load(String roleName) throws Exception {
                return makeExpensiveCallToGetAllEmployeesByRoleName(roleName);
            }
        });

public Collection<Person> getAllEmployeesByRole(String roleName) {
    return employeeRoleLoadingCache.getUnchecked(roleName);
}

In the above example, we cache all employees for each given role for a day. Further, we configure the cache to store up to 1000 elements before evicting the older cached element.

Guava: Elegant Collection Ordering

PROBLEM

Java provides a built-in API to sort a list, but it is flat out ugly and prone to error especially when dealing with Comparator. Here’s an example:-

List<Request> allRequests = ...;

Collections.sort(allRequests, new Comparator<Request>() {
    @Override
    public int compare(Request lhs, Request rhs) {
        if (lhs.getSubmissionDatetime() == null) {
            return -1;
        }
        else if (rhs.getSubmissionDatetime() == null) {
            return 1;
        }

        return lhs.getSubmissionDatetime().compareTo(rhs.getSubmissionDatetime());
    }
});

Number of puppies killed = 3 … from the if-else statement.

SOLUTION

A better way to do this is to use Ordering from Guava:-

List<Request> allRequests = ...;

List<Request> sortedRequests = Ordering.natural()
        .nullsFirst()
        .onResultOf(new Function<Request, LocalDateTime>() {
            @Override
            public LocalDateTime apply(Request request) {
                return request.getSubmissionDatetime();
            }
        })
        .immutableSortedCopy(allRequests);

In this example, we want all the null elements to appear on top of the list. We can also use nullsLast() if we want them to be at the bottom of the list.

Number of puppies killed = 0.

Java: Performing 2-Key Lookup using HashBasedTable

PROBLEM

HashMap is great to perform a simple lookup, for example:-

Map<String, String> map = new HashMap<String, String>();
map.put("key", "mike");

String value = map.get("key"); // "mike"

However, what if we need 2 keys to lookup a value? For example, we need “key1” + “key2” in order to lookup “mike”.

SOLUTION 1: Create combo key

You can combine the keys to create a unique key:-

Map<String, String> map = new HashMap<String, String>();
map.put("key1|key2", "mike");

String value = map.get("key1|key2"); // "mike"

Assuming if the keys are just characters, this works fine. However, this solution might not work too well if the keys are objects, like Person object, etc.

SOLUTION 2: Create key as an object

In this solution, we leverage Apache Commons’ MultiKey to create the combo key:-

Map<MultiKey, String> map = new HashMap<MultiKey, String>();
map.put(new MultiKey("key1", "key2"), "mike");

String value = map.get(new MultiKey("key1", "key2")); // "mike"

This solution works a little better than the first solution, but the code looks just plain ugly to read.

SOLUTION 3: Using Map of Map

In this solution, we use Map of Map to accomplish the 2-key lookup:-

Map<String, Map<String, String>> map = new HashMap<String, Map<String, String>>();

Map<String, String> innnerMap = new HashMap<String, String>();
innnerMap.put("key2", "mike");

map.put("key1", innnerMap);

String value = map.get("key1").get("key2"); // "mike"

This solution obviously offers tons of flexibility, but it is shit difficult to read… and sadly, I myself implemented something like this in the past. In my opinion, this solution is too complicated for what we are trying to achieve here. We also have to worry about whether map.get(firstKey) will return null, which may cause NullPointerException if we chain the call to lookup the second key.

SOLUTION 4: Using HashBasedTable

The most elegant solution in my opinion is to utilize Google Guava’s HashBasedTable:-

HashBasedTable<String, String, String> hashBasedTable = HashBasedTable.create();
hashBasedTable.put("key1", "key2", "mike");

String value = hashBasedTable.get("key1", "key2"); // "mike"

This is probably the cleanest solution to perform 2-key lookup. Based on the documentation, HashBasedTable itself is using Map of Map under the cover.