Reducing Java Boilerplate
October 20th, 2009 by SamOne of the darker sides of Java is the boilerplate; lines and lines of boring, repetitious and ugly boilerplate. In this post, we show how to reduce/hide boilerplate and increase the readability of your Java code under the following circumstances:
- argument checking, with exception throwing
equalsandhashCode- providing getters and setters (the JavaBean pattern)
resulting in making your code more coherent .
Argument checking
The Google Collections provides a superb adjunct library to the Java Standard Library. Among the library is the beautiful convenience class Preconditions, full of static methods for testing conditions, throwing exceptions on failure. The following examples, interspersed with comments, demonstrates use
// bounds on integer, failure throws IllegalArgumentException
Preconditions.checkArgument(a > 0 && a <= 10);
// same as above, include value of 'a' in exception
Preconditions.checkArgument(a > 0 && a <= 10, a);
// use a static import and a formatter for output
checkArgument(count > 0, "must be positive: %s", count);
// throws NullPointerException if 'obj' is null
Preconditions.checkNotNull(obj);
// same as above but include string "obj" in exception
Preconditions.checkNotNull(obj, "obj");
contrast to how the same would be written without the convenience class. The vanilla boilerplate is so tedious, it is tempting to forego it.
if (!(a > 0 && a <= 10)) {
throw new IllegalArgumentException();
}
if (!(a > 0 && a <= 10)) {
throw new IllegalArgumentException(Integer.toString(a));
}
if (count <= 0) {
throw new IllegalArgumentException(String.format("must be positive: %s", count));
}
if (obj == null) {
throw new NullPointerException();
}
if (obj == null) {
throw new NullPointerException("obj");
}
Using the Google Collections therefore encourages argument checking and, by implication, early detection of bugs.
equals and hashCode
Every good Java programmer should read Josh Bloch’s Effective Java and know the rules when overriding equals and hashCode. Although many modern IDEs simplify this by auto-generating boilerplate, the result is always hideous.
However, Google Collections provides static convenience methods in Objects which allow us to produce readable code. Consider Brian Goetz’s example from the IBM tutorial
@Override
public boolean equals(Object other) {
if (this == other)
return true;
if (!(other instanceof A))
return false;
A otherA = (A) other;
return
(someNonNullField.equals(otherA.someNonNullField))
&& ((someOtherField == null)
? otherA.someOtherField == null
: someOtherField.equals(otherA.someOtherField)));
}
@Override
public int hashCode() {
int hash = 1;
hash = hash * 31 + someNonNullField.hashCode();
hash = hash * 31
+ (someOtherField == null ? 0 : someOtherField.hashCode());
return hash;
}
whereas the Google Collections equivalent is
@Override
public boolean equals(Object other) {
if (this == other)
return true;
if (!(other instanceof A))
return false;
A otherA = (A) other;
return Objects.equal(someNonNullField, otherA.someNonNullField)
&& Objects.equal(someOtherField, otherA.someOtherField);
}
@Override
public int hashCode() {
return Objects.hashCode(someNonNullField, someOtherField);
}
Admittedly, that’s a lot of code to say two objects are equal, but it’s certainly more readable. In NetBeans, consider writing a Code Template to provide the reduced boilerplate outline.
If you are not happy having to look at this much code, consider combining with the final hint, for hiding getters and setters, perhaps even just for the first five lines of the equals method. The following is my NetBeans Code Template for equals and hashCode
@Override
public boolean equals(Object obj) {
// <editor-fold defaultstate="collapsed" desc="boilerplate identity, instanceof and cast">
if (this == obj)
return true;
if (!(obj instanceof ${TYPE default="Object"}))
return false;
final ${TYPE default="Object"} other = (${TYPE default="Object"}) obj;// </editor-fold>
return Objects.equal(a, other.a);
}
@Override
public int hashCode() {
return Objects.hashCode(a);
}
Getters and Setters
The JavaBeans pattern is a real bore. It demands getter and setter methods (with their own Javadocs!) to go along with fields… that’s 14 lines of code additional to every field you want to make available!
There is no way to get around writing this code. I recommend getting your IDE to auto-generate it. However, in NetBeans it is possible to wrap large portions of your files in Editor Fold comments, like so
// <editor-fold defaultstate="collapsed" desc="boilerplate">
/**
* @return
*/
public A getA() {
return a;
}
/**
* @param a
*/
public void setA(A a) {
this.a = a;
}
//</editor-fold>
and, so long as Preferences -> Editor -> General -> Code Folding is enabled, the code is folded up and hidden away from view. Only a line of text, labelled boilerplate appears in your file, and it can be uncovered with a single click.
Paul Butcher wrote:
October 21st, 2009 at 11:40 am