Thứ Bảy, 12 tháng 10, 2013

Too Many Parameters in Java Methods, Part 3: Builder Pattern

In my two immediately previous posts, I looked at reducing the number of parameters required for a constructor or method invocation via custom types and parameter objects. In this post, I look at use of the builder pattern to reduce the number of parameters required for a constructor with some discussion on how this pattern can even help with non-constructor methods that take too many parameters.

In the Second Edition of Effective Java, Josh Bloch introduces use of the builder pattern in Item #2 for dealing with constructors that require too many parameters. Bloch not only demonstrates how to use the Builder, but explains it advantages over constructors accepting a large number of parameters. I will get to those advantages at the end of this post, but think it's important to point out that Bloch has devoted an entire item in his book to this practice.

To illustrate the advantages of this approach, I'll use the following example Person class. It doesn't have all the methods I would typically add to such a class because I want to focus on its construction.

Person.java (without Builder Pattern)

package dustin.examples;

/**
* Person class used as part of too many parameters demonstration.
*
* @author Dustin
*/
public class Person
{
private final String lastName;
private final String firstName;
private final String middleName;
private final String salutation;
private final String suffix;
private final String streetAddress;
private final String city;
private final String state;
private final boolean isFemale;
private final boolean isEmployed;
private final boolean isHomewOwner;

public Person(
final String newLastName,
final String newFirstName,
final String newMiddleName,
final String newSalutation,
final String newSuffix,
final String newStreetAddress,
final String newCity,
final String newState,
final boolean newIsFemale,
final boolean newIsEmployed,
final boolean newIsHomeOwner)
{
this.lastName = newLastName;
this.firstName = newFirstName;
this.middleName = newMiddleName;
this.salutation = newSalutation;
this.suffix = newSuffix;
this.streetAddress = newStreetAddress;
this.city = newCity;
this.state = newState;
this.isFemale = newIsFemale;
this.isEmployed = newIsEmployed;
this.isHomewOwner = newIsHomeOwner;
}
}

This class's constructor works, but it is difficult for client code to use properly. The Builder pattern can be used to make the constructor easier to use. NetBeans will refactor this for me as I have written about previously. An example of the refactored code is shown next (NetBeans does this by creating all new Builder class).

PersonBuilder.java

package dustin.examples;


public class PersonBuilder
{
private String newLastName;
private String newFirstName;
private String newMiddleName;
private String newSalutation;
private String newSuffix;
private String newStreetAddress;
private String newCity;
private String newState;
private boolean newIsFemale;
private boolean newIsEmployed;
private boolean newIsHomeOwner;

public PersonBuilder()
{
}

public PersonBuilder setNewLastName(String newLastName) {
this.newLastName = newLastName;
return this;
}

public PersonBuilder setNewFirstName(String newFirstName) {
this.newFirstName = newFirstName;
return this;
}

public PersonBuilder setNewMiddleName(String newMiddleName) {
this.newMiddleName = newMiddleName;
return this;
}

public PersonBuilder setNewSalutation(String newSalutation) {
this.newSalutation = newSalutation;
return this;
}

public PersonBuilder setNewSuffix(String newSuffix) {
this.newSuffix = newSuffix;
return this;
}

public PersonBuilder setNewStreetAddress(String newStreetAddress) {
this.newStreetAddress = newStreetAddress;
return this;
}

public PersonBuilder setNewCity(String newCity) {
this.newCity = newCity;
return this;
}

public PersonBuilder setNewState(String newState) {
this.newState = newState;
return this;
}

public PersonBuilder setNewIsFemale(boolean newIsFemale) {
this.newIsFemale = newIsFemale;
return this;
}

public PersonBuilder setNewIsEmployed(boolean newIsEmployed) {
this.newIsEmployed = newIsEmployed;
return this;
}

public PersonBuilder setNewIsHomeOwner(boolean newIsHomeOwner) {
this.newIsHomeOwner = newIsHomeOwner;
return this;
}

public Person createPerson() {
return new Person(newLastName, newFirstName, newMiddleName, newSalutation, newSuffix, newStreetAddress, newCity, newState, newIsFemale, newIsEmployed, newIsHomeOwner);
}

}

I prefer to have my Builder as a nested class inside the class whose object it builds, but the NetBeans automatic generation of a standalone Builder is very easy to use. Another difference between the NetBeans-generated Builder and the Builders I like to write is that my preferred Builder implementations have required fields provided in the Builder's constructor rather than provide a no-arguments constructor. The next code listing shows my Person class from above with a Builder added into it as a nested class.

Person.java with Nested Person.Builder

package dustin.examples;

/**
* Person class used as part of too many parameters demonstration.
*
* @author Dustin
*/
public class Person
{
private final String lastName;
private final String firstName;
private final String middleName;
private final String salutation;
private final String suffix;
private final String streetAddress;
private final String city;
private final String state;
private final boolean isFemale;
private final boolean isEmployed;
private final boolean isHomewOwner;

public Person(
final String newLastName,
final String newFirstName,
final String newMiddleName,
final String newSalutation,
final String newSuffix,
final String newStreetAddress,
final String newCity,
final String newState,
final boolean newIsFemale,
final boolean newIsEmployed,
final boolean newIsHomeOwner)
{
this.lastName = newLastName;
this.firstName = newFirstName;
this.middleName = newMiddleName;
this.salutation = newSalutation;
this.suffix = newSuffix;
this.streetAddress = newStreetAddress;
this.city = newCity;
this.state = newState;
this.isFemale = newIsFemale;
this.isEmployed = newIsEmployed;
this.isHomewOwner = newIsHomeOwner;
}

public static class PersonBuilder
{
private String nestedLastName;
private String nestedFirstName;
private String nestedMiddleName;
private String nestedSalutation;
private String nestedSuffix;
private String nestedStreetAddress;
private String nestedCity;
private String nestedState;
private boolean nestedIsFemale;
private boolean nestedIsEmployed;
private boolean nestedIsHomeOwner;

public PersonBuilder(
final String newFirstName,
final String newCity,
final String newState)
{
this.nestedFirstName = newFirstName;
this.nestedCity = newCity;
this.nestedState = newState;
}

public PersonBuilder lastName(String newLastName)
{
this.nestedLastName = newLastName;
return this;
}

public PersonBuilder firstName(String newFirstName)
{
this.nestedFirstName = newFirstName;
return this;
}

public PersonBuilder middleName(String newMiddleName)
{
this.nestedMiddleName = newMiddleName;
return this;
}

public PersonBuilder salutation(String newSalutation)
{
this.nestedSalutation = newSalutation;
return this;
}

public PersonBuilder suffix(String newSuffix)
{
this.nestedSuffix = newSuffix;
return this;
}

public PersonBuilder streetAddress(String newStreetAddress)
{
this.nestedStreetAddress = newStreetAddress;
return this;
}

public PersonBuilder city(String newCity)
{
this.nestedCity = newCity;
return this;
}

public PersonBuilder state(String newState)
{
this.nestedState = newState;
return this;
}

public PersonBuilder isFemale(boolean newIsFemale)
{
this.nestedIsFemale = newIsFemale;
return this;
}

public PersonBuilder isEmployed(boolean newIsEmployed)
{
this.nestedIsEmployed = newIsEmployed;
return this;
}

public PersonBuilder isHomeOwner(boolean newIsHomeOwner)
{
this.nestedIsHomeOwner = newIsHomeOwner;
return this;
}

public Person createPerson()
{
return new Person(
nestedLastName, nestedFirstName, nestedMiddleName,
nestedSalutation, nestedSuffix,
nestedStreetAddress, nestedCity, nestedState,
nestedIsFemale, nestedIsEmployed, nestedIsHomeOwner);
}
}
}

The Builder can be even nicer when enhanced through use of custom types and parameters objects as outlined in my first two posts on the "too many parameters" problem. This is shown in the next code listing.

Person.java with Nested Builder, Custom Types, and Parameters Object

package dustin.examples;

/**
* Person class used as part of too many parameters demonstration.
*
* @author Dustin
*/
public class Person
{
private final FullName name;
private final Address address;
private final Gender gender;
private final EmploymentStatus employment;
private final HomeownerStatus homeOwnerStatus;

/**
* Parameterized constructor can be private because only my internal builder
* needs to call me to provide an instance to clients.
*
* @param newName Name of this person.
* @param newAddress Address of this person.
* @param newGender Gender of this person.
* @param newEmployment Employment status of this person.
* @param newHomeOwner Home ownership status of this person.
*/
private Person(
final FullName newName, final Address newAddress,
final Gender newGender, final EmploymentStatus newEmployment,
final HomeownerStatus newHomeOwner)
{
this.name = newName;
this.address = newAddress;
this.gender = newGender;
this.employment = newEmployment;
this.homeOwnerStatus = newHomeOwner;
}

public FullName getName()
{
return this.name;
}

public Address getAddress()
{
return this.address;
}

public Gender getGender()
{
return this.gender;
}

public EmploymentStatus getEmployment()
{
return this.employment;
}

public HomeownerStatus getHomeOwnerStatus()
{
return this.homeOwnerStatus;
}

/**
* Builder class as outlined in the Second Edition of Joshua Bloch's
* Effective Java that is used to build a {@link Person} instance.
*/
public static class PersonBuilder
{
private FullName nestedName;
private Address nestedAddress;
private Gender nestedGender;
private EmploymentStatus nestedEmploymentStatus;
private HomeownerStatus nestedHomeOwnerStatus;

public PersonBuilder(
final FullName newFullName,
final Address newAddress)
{
this.nestedName = newFullName;
this.nestedAddress = newAddress;
}

public PersonBuilder name(final FullName newName)
{
this.nestedName = newName;
return this;
}

public PersonBuilder address(final Address newAddress)
{
this.nestedAddress = newAddress;
return this;
}

public PersonBuilder gender(final Gender newGender)
{
this.nestedGender = newGender;
return this;
}

public PersonBuilder employment(final EmploymentStatus newEmploymentStatus)
{
this.nestedEmploymentStatus = newEmploymentStatus;
return this;
}

public PersonBuilder homeOwner(final HomeownerStatus newHomeOwnerStatus)
{
this.nestedHomeOwnerStatus = newHomeOwnerStatus;
return this;
}

public Person createPerson()
{
return new Person(
nestedName, nestedAddress, nestedGender,
nestedEmploymentStatus, nestedHomeOwnerStatus);
}
}
}

The last couple of code listings show how a Builder is typically used - to construct an object. Indeed, the item on the builder (Item #2) in Joshua Bloch's Second Edition of Effective Java is in the chapter on creating (and destroying) object. However, the builder can help indirectly with non-constructor methods by allowing an easier way to build parameters objects that are passed to methods.

For example, in the last code listing, the methods have some parameters objects (FullName and Address) passed to them. It can be tedious for clients to have to construct these parameters objects and the builder can be used to make that process less tedious. So, although the builder is used for construction in each case, it indirectly benefits non-constructor methods by allowing for easier use of the parameters objects that reduce a method's argument count.

The new definitions of the FullName and Address classes to be used as parameters objects and using the Builder themselves are shown next.

FullName.java with Builder

package dustin.examples;

/**
* Full name of a person.
*
* @author Dustin
*/
public final class FullName
{
private final Name lastName;
private final Name firstName;
private final Name middleName;
private final Salutation salutation;
private final Suffix suffix;

private FullName(
final Name newLastName,
final Name newFirstName,
final Name newMiddleName,
final Salutation newSalutation,
final Suffix newSuffix)
{
this.lastName = newLastName;
this.firstName = newFirstName;
this.middleName = newMiddleName;
this.salutation = newSalutation;
this.suffix = newSuffix;
}

public Name getLastName()
{
return this.lastName;
}

public Name getFirstName()
{
return this.firstName;
}

public Name getMiddleName()
{
return this.middleName;
}

public Salutation getSalutation()
{
return this.salutation;
}

public Suffix getSuffix()
{
return this.suffix;
}

@Override
public String toString()
{
return this.salutation + " " + this.firstName + " " + this.middleName
+ this.lastName + ", " + this.suffix;
}

public static class FullNameBuilder
{
private final Name nestedLastName;
private final Name nestedFirstName;
private Name nestedMiddleName;
private Salutation nestedSalutation;
private Suffix nestedSuffix;

public FullNameBuilder(
final Name newLastName, final Name newFirstName)
{
this.nestedLastName = newLastName;
this.nestedFirstName = newFirstName;
}

public FullNameBuilder middleName(final Name newMiddleName)
{
this.nestedMiddleName = newMiddleName;
return this;
}

public FullNameBuilder salutation(final Salutation newSalutation)
{
this.nestedSalutation = newSalutation;
return this;
}

public FullNameBuilder suffix(final Suffix newSuffix)
{
this.nestedSuffix = newSuffix;
return this;
}

public FullName createFullName()
{
return new FullName(
nestedLastName, nestedFirstName, nestedMiddleName,
nestedSalutation, nestedSuffix);
}
}
}
Address.java with Builder

package dustin.examples;

/**
* Representation of a United States address.
*
* @author Dustin
*/
public final class Address
{
private final StreetAddress streetAddress;
private final City city;
private final State state;

private Address(final StreetAddress newStreetAddress, final City newCity, final State newState)
{
this.streetAddress = newStreetAddress;
this.city = newCity;
this.state = newState;
}

public StreetAddress getStreetAddress()
{
return this.streetAddress;
}

public City getCity()
{
return this.city;
}

public State getState()
{
return this.state;
}

@Override
public String toString()
{
return this.streetAddress + ", " + this.city + ", " + this.state;
}

public static class AddressBuilder
{
private StreetAddress nestedStreetAddress;
private final City nestedCity;
private final State nestedState;

public AddressBuilder(final City newCity, final State newState)
{
this.nestedCity = newCity;
this.nestedState = newState;
}

public AddressBuilder streetAddress(final StreetAddress newStreetAddress)
{
this.nestedStreetAddress = newStreetAddress;
return this;
}

public Address createAddress()
{
return new Address(nestedStreetAddress, nestedCity, nestedState);
}
}
}

With the above builders included in the classes, a Person instance can be created as shown in the next code listing. A more traditional instantiation of a Person instance is shown after that for comparison.

Two Examples of Client Code Instantiating a Person with Builders

final Person person1 = new Person.PersonBuilder(
new FullName.FullNameBuilder(
new Name("Dynamite"), new Name("Napoleon")).createFullName(),
new Address.AddressBuilder(
new City("Preston"), State.ID).createAddress()).createPerson();

final Person person2 = new Person.PersonBuilder(
new FullName.FullNameBuilder(
new Name("Coltrane"), new Name("Rosco")).middleName(new Name("Purvis")).createFullName(),
new Address.AddressBuilder(
new City("Hazzard"), State.GA).createAddress())
.gender(Gender.MALE).employment(EmploymentStatus.EMPLOYED).createPerson();
Instantiating a Person Without a Builder

final person = new Person("Coltrane", "Rosco", "Purvis", null, "Hazzard", "Georgia", false, true, true);

As the previous code snippets show, the client code for calling a traditional Java constructor is far less readable and far easier to mess up than use of the builder classes. The variety of the same types (strings and booleans) and the necessity to place nulls in the constructor call for optional attributes make provide many ways for this approach to end badly.

Benefits and Advantages

There is a considerable cost to the Builder pattern in that one must essentially double the number of lines of code each attribute and for setting those attributes. This price pays off, however, when the client code benefits greatly in terms of usability and readability. The parameters to the constructor are reduced and are provided in highly readable method calls.

Another advantage of the Builder approach is the ability to acquire an object in a single statement and state without the object in multiple states problem presented by using "set" methods. I am increasingly appreciating the value of immutability in a multi-core world and the Builder pattern is perfectly suited for an immutable class when that class features a large number of attributes. I also like that there is no need to pass in null for optional parameters to the constructor.

The Builder pattern not only makes the code more readable, but makes it even easier to apply an IDE's code completion feature. Further benefits of the Builder pattern when used with constructors are outlined in Item #2 of the Second Edition of Effective Java.

Costs and Disadvantages

As shown and mentioned above, the number of lines of code of a given class must be essentially doubled for "set" methods with the builder approach. Furthermore, although client code is more readable, the client code is also more verbose. I consider the benefit of greater readability worth the cost as the number of arguments increase or as more arguments share the same type or as the number of optional arguments increase.

More lines of code in the class with the builder sometimes mean that developers may forget to add support for a new attribute to the builder when they add that attribute to the main class. To try to help with this, I like to nest my builders inside the class that they build so that it's more obvious to the developer that there is a relevant builder that needs to be similarly updated. Although there is still risk of the developer forgetting to add support for a new attribute to the builder, this is really no different than the risk of forgetting to add a new attribute to a class's toString(), equals(Object), hashCode() or other methods often based on all attributes of a class.

In my implementation of the Builder, I made the client pass required attributes into the builder's constructor rather than via "set" methods. The advantage of this is that the object is always instantiated in a "complete" state rather than sitting in an incomplete state until the developer calls (if ever calls) the appropriate "set" method to set additional fields. This is necessary to enjoy the benefits of immutability. However, a minor disadvantage of that approach is that I don't get the readability advantages of methods named for the field I am setting.

The Builder, as its name suggests, is really only an alternative to constructors and not directly used to reduce the number of non-constructor method parameters. However, the builder can be used in conjunction with parameters objects to reduce the number of non-constructor method arguments. Further arguments against use of the Builder for object construction can be found in a comment on the A dive into the Builder pattern post.

Conclusion

I really like the Builder pattern for constructing objects when I have a lot of parameters, especially if many of these parameters are null and when many of them share the same data type. A developer might feel that the extra code to implement a Builder might not justify its benefits for a small number of parameters, especially if the few parameters are required and of different types. In such cases, it might be considered desirable to use traditional constructors or, if immutability is not desired, use a no-argument constructor and require the client to know to call the necessary "set" methods.

Thứ Tư, 9 tháng 10, 2013

Too Many Parameters in Java Methods, Part 2: Parameters Object

In my previous post, I looked at some of the problems associated with long parameters lists for methods and constructors. In that post, I discussed replacing primitives and built-in types with custom types to improve readability and type safety. That approached made the numerous parameters to a method or constructor more readable, but did nothing to reduce the number of parameters. In this post, I look at use of a Parameter Object to reduce the number of parameters to a method or constructor.

It is generally not a good idea to make "junk drawer" objects that couple unrelated parameters whose only relationship to one another is that they need to be passed to the same method or constructor. However, when related parameters are being passed to a constructor or method as part of a highly cohesive object, the refactoring known as Introduce Parameter Object is a nice solution. This refactoring's usage is described as "group[ing] of parameters that naturally go together." I will demonstrate this refactoring in this post.

To demonstrate the utility of the Introduce Parameter Object refactoring, let's first look at the example from the last post which uses numerous String and boolean parameters in a method call.


/**
* Instantiate a Person object.
*
* @param lastName
* @param firstName
* @param middleName
* @param salutation
* @param suffix
* @param streetAddress
* @param city
* @param state
* @param isFemale
* @param isEmployed
* @param isHomeOwner
* @return
*/
public Person createPerson(
final String lastName,
final String firstName,
final String middleName,
final String salutation,
final String suffix,
final String streetAddress,
final String city,
final String state,
final boolean isFemale,
final boolean isEmployed,
final boolean isHomeOwner)
{
// implementation goes here
}

As I discussed in the previous post, this approach is tedious for callers, makes it all too easy to pass parameters in the wrong order with little type safety, and can reduce readability of the code. Fortunately, the parameters in this example provide some good opportunities to apply the Introduce Parameter Object refactoring. The "names" parameters (including salutation and suffix) could be included in a single full name class. The address parameters (street address, city, and state) could be in a single address object. The other parameters might not be so easily grouped into a single class with high cohesion.

With the suggested applications of the Introduce Parameter Object refactoring, the previously shown method call is simpler thanks to the reduced number of parameters. This is shown in the next code listing.


public Person createPerson(
final FullName fullName,
final Address address,
final boolean isFemale,
final boolean isEmployed,
final boolean isHomeOwner)
{
return new Person();
}

The above example now only has five parameters and is more readable and easier to use by clients. It is also more safe from a typing perspective as it is nearly impossible to confuse strings of names with strings of address in this case. Unfortunately, the three boolean parameters remain a source of potential confusion and cloud readability a bit. The next code listings show potential implementations of the FullName and Address classes.

FullName.java (Simple)

package dustin.examples;

/**
* Full name of a person.
*
* @author Dustin
*/
public final class FullName
{
private final String lastName;
private final String firstName;
private final String middleName;
private final String salutation;
private final String suffix;

public FullName(
final String newLastName,
final String newFirstName,
final String newMiddleName,
final String newSalutation,
final String newSuffix)
{
this.lastName = newLastName;
this.firstName = newFirstName;
this.middleName = newMiddleName;
this.salutation = newSalutation;
this.suffix = newSuffix;
}

public String getLastName()
{
return this.lastName;
}

public String getFirstName()
{
return this.firstName;
}

public String getMiddleName()
{
return this.middleName;
}

public String getSalutation()
{
return this.salutation;
}

public String getSuffix()
{
return this.suffix;
}

@Override
public String toString()
{
return this.salutation + " " + this.firstName + " " + this.middleName
+ this.lastName + ", " + this.suffix;
}
}
Address.java (Simple)

package dustin.examples;

/**
* Representation of a United States address.
*
* @author Dustin
*/
public final class Address
{
private final String streetAddress;
private final String city;
private final String state;

public Address(final String newStreetAddress, final String newCity, final String newState)
{
this.streetAddress = newStreetAddress;
this.city = newCity;
this.state = newState;
}

public String getStreetAddress()
{
return this.streetAddress;
}

public String getCity()
{
return this.city;
}

public String getState()
{
return this.state;
}

@Override
public String toString()
{
return this.streetAddress + ", " + this.city + ", " + this.state;
}
}

Although the code is improved, there are still some issues that can be improved. In particular, the original method with too many parameters still has three boolean parameters that can be easily confused with one another. Although the String parameters to that method were factored into two new classes, those two new classes still each consist of a bunch of Strings. In these cases, one might want to supplement the Introduce Parameter Object refactoring with use of custom types. Using the custom types I showed in my last post, the method with too many parameters now looks like that shown in the next code listing.


public Person createPerson(
final FullName fullName,
final Address address,
final Gender gender,
final EmploymentStatus employment,
final HomeownerStatus homeownerStatus)
{
// implementation goes here
}

The method now has fewer parameters and the parameters it does have are all of distinct types. IDEs and the Java compiler can now be especially helpful in ensuring that clients use this interface properly. Applying custom types (written in last post) to the FullName and Address classes result in the next two new code listings for those classes.

FullName.java (Custom Types)

package dustin.examples;

/**
* Full name of a person.
*
* @author Dustin
*/
public final class FullName
{
private final Name lastName;
private final Name firstName;
private final Name middleName;
private final Salutation salutation;
private final Suffix suffix;

public FullName(
final Name newLastName,
final Name newFirstName,
final Name newMiddleName,
final Salutation newSalutation,
final Suffix newSuffix)
{
this.lastName = newLastName;
this.firstName = newFirstName;
this.middleName = newMiddleName;
this.salutation = newSalutation;
this.suffix = newSuffix;
}

public Name getLastName()
{
return this.lastName;
}

public Name getFirstName()
{
return this.firstName;
}

public Name getMiddleName()
{
return this.middleName;
}

public Salutation getSalutation()
{
return this.salutation;
}

public Suffix getSuffix()
{
return this.suffix;
}

@Override
public String toString()
{
return this.salutation + " " + this.firstName + " " + this.middleName
+ this.lastName + ", " + this.suffix;
}
}
Address.java (Custom Types)

package dustin.examples;

/**
* Representation of a United States address.
*
* @author Dustin
*/
public final class Address
{
private final StreetAddress streetAddress;
private final City city;
private final State state;

public Address(final StreetAddress newStreetAddress, final City newCity, final State newState)
{
this.streetAddress = newStreetAddress;
this.city = newCity;
this.state = newState;
}

public StreetAddress getStreetAddress()
{
return this.streetAddress;
}

public City getCity()
{
return this.city;
}

public State getState()
{
return this.state;
}

@Override
public String toString()
{
return this.streetAddress + ", " + this.city + ", " + this.state;
}
}

All of my examples thus far have been of standalone public classes. I often find that if I need a parameter object simply for passing information between methods and constructors in the same package that it can be useful to make these parameter object classes package scope. Nested classes can also be used for these parameter objects in some cases.

Benefits and Advantages

The most obvious benefit of the parameter object is the reduction in number of parameters passed to a method or constructor. This encapsulation of related parameters makes it easier to quickly ascertain what types are being passed to the method or constructor. It is easier for a developer to understand a smaller number of parameters.

Parameter objects share one of the same benefits provided by custom types: the ability to add additional behaviors and characteristics to the parameter object for convenience functions. For example, having an Address class rather than a bunch of String types allows one to validate addresses.

Costs and Disadvantages

The primary drawback to the parameter object is a little extra work to design, implement, and test the class. However, these are pretty easy to write and test and modern tools such as IDEs and scripting languages make it even easier to automate the most mundane and tedious portions of those tasks. An even smaller argument against this approach is that it can be abused. If a developer starts bundling unrelated parameters together into a class just to reduce the number of parameters, that doesn't necessarily help the situation. That approach does indeed reduce the number of parameters, but the ultimate goal of improving readability is not achieved and it could be argued that this approach is even less readable.

Conclusion

Parameter objects provide a nice clean approach to appropriately encapsulating related parameters to reduce the total parameter count to a method or constructor. They are easy to implement and can significantly enhance the readability and type safety parameters passed to method and constructor calls. Parameter objects can be enhanced further through the use of custom types as explained in my previous post.

Thứ Hai, 7 tháng 10, 2013

Too Many Parameters in Java Methods, Part 1: Custom Types

I consider lengthy parameters lists in constructors and methods to be another "red flag" in Java development that may not necessarily be "wrong" in terms of logic and functionality, but often hint at the high possibility of current or future errors. In a small series of posts, I look at some of the approaches that can be used to reduce the numbers of parameters to methods or constructors or to at least make lengthy lists of parameters more readable and less error-prone. Each approach has its own set of advantages and disadvantages. This post begins that series with focus on improving the readability and safety of a long method/constructor parameter list via the use of custom types.

Lengthy lists of parameters to methods and constructors have several drawbacks. A large number of parameters can be tedious and difficult for calling code to use. Long lists of parameters can also lead to inadvertent switching of parameters in invocations. These bugs can be difficult to find in certain cases. Fortunately, most of don't have to deal with another disadvantage of lengthy parameter lists: the JVM limiting the number of parameters to a method via compile-time error.

One approach that does not reduce the number of parameters to a method or constructor, but that does make these long parameter lists more readable and less likely to be provided in the wrong order, is the use of custom types. These custom types might be implemented as Data Transfer Objects (DTOs), as JavaBeans, as Value Objects, as Reference Objects, or any other custom type (in Java, typically a class or enum).

Here is a contrived example of a method that accepts several parameters, many of type String and many of type boolean.


/**
* Instantiate a Person object.
*
* @param lastName
* @param firstName
* @param middleName
* @param salutation
* @param suffix
* @param streetAddress
* @param city
* @param state
* @param isFemale
* @param isEmployed
* @param isHomeOwner
* @return
*/
public Person createPerson(
final String lastName,
final String firstName,
final String middleName,
final String salutation,
final String suffix,
final String streetAddress,
final String city,
final String state,
final boolean isFemale,
final boolean isEmployed,
final boolean isHomeOwner)
{
// implementation goes here
}

It is easy to switch these accidentally and pass them in the wrong order. Although I generally would prefer to reduce the parameters, some improvement can be made by varying the types in the parameter list. The next code listings show some examples of these custom types that can be used for names, addresses, city, and the boolean parameters.

The three name parameters can each be changed to a custom type of Name rather than String. That Name type is defined next.

Name.java

package dustin.examples;

/**
* Name representation.
*
* @author Dustin
*/
public final class Name
{
private final String name;

public Name(final String newName)
{
this.name = newName;
}

public String getName()
{
return this.name;
}

@Override
public String toString()
{
return this.name;
}
}

The salutation and suffix String types can also be replaced with custom types as shown in the next two code listings.

Salutation.java

package dustin.examples;

/**
* Salutations for individuals' names.
*
* @author Dustin
*/
public enum Salutation
{
DR,
MADAM,
MISS,
MR,
MRS,
MS,
SIR
}
Suffix.java

package dustin.examples;

/**
* Suffix representation.
*
* @author Dustin
*/
public enum Suffix
{
III,
IV,
JR,
SR
}

The other parameters could also be replaced by custom types. The next code listings show custom enums that can replace the booleans to improve readability.

Gender.java

package dustin.examples;

/**
* Gender representation.
*
* @author Dustin
*/
public enum Gender
{
FEMALE,
MALE
}
EmploymentStatus.java

package dustin.examples;

/**
* Representation of employment status.
*
* @author Dustin
*/
public enum EmploymentStatus
{
EMPLOYED,
NOT_EMPLOYED
}
HomeOwnerStatus.java

package dustin.examples;

/**
* Representation of homeowner status.
*
* @author Dustin
*/
public enum HomeownerStatus
{
HOME_OWNER,
RENTER
}

The address information for this person can also be passed in using custom types defined as shown in the next code listings.

StreetAddress.java

package dustin.examples;

/**
* Street Address representation.
*
* @author Dustin
*/
public final class StreetAddress
{
private final String address;

public StreetAddress(final String newStreetAddress)
{
this.address = newStreetAddress;
}

public String getAddress()
{
return this.address;
}

@Override
public String toString()
{
return this.address;
}
}
City.java

package dustin.examples;

/**
* City representation.
*
* @author Dustin
*/
public final class City
{
private final String cityName;

public City(final String newCityName)
{
this.cityName = newCityName;
}

public String getCityName()
{
return this.cityName;
}

@Override
public String toString()
{
return this.cityName;
}
}
State.java

package dustin.examples;

/**
* Simple representation of a state in the United States.
*
* @author Dustin
*/
public enum State
{
AK,
AL,
AR,
AZ,
CA,
CO,
CT,
DE,
FL,
GA,
HI,
IA,
ID,
IL,
IN,
KS,
KY,
LA,
MA,
MD,
ME,
MI,
MN,
MO,
MS,
MT,
NC,
ND,
NE,
NH,
NJ,
NM,
NV,
NY,
OH,
OK,
OR,
PA,
RI,
SC,
SD,
TN,
TX,
UT,
VA,
VT,
WA,
WI,
WV,
WY
}

With these custom types implemented, the signature of our original method becomes much more readable and less likely to have parameters accidentally provided in the wrong order. This is shown in the next code listing.


public Person createPerson(
final Name lastName,
final Name firstName,
final Name middleName,
final Salutation salutation,
final Suffix suffix,
final StreetAddress address,
final City city,
final State state,
final Gender gender,
final EmploymentStatus employment,
final HomeownerStatus homeowner)
{
// implementation goes here
}

In the code listing above, the compiler will now aid the developer by not allowing most of the previous String or boolean parameters to be accidentally mixed in order. The three names are still a potential issue as the caller could provide them out of order, but I could have written specific types (classes) for FirstName, LastName, and MiddleName if I was concerned about that. My preference instead is to use a new class that represents a full name and has all three of those names as its attributes, but that approach will be the topic of a future post on dealing with too many parameters to a Java method.

Benefits and Advantages

The advantages of writing and using custom types when dealing with multiple parameters on a given method include readability for the code maintainer and for the developer using the API. Having multiple parameters of the same type not only makes it easy for the developer to mix up their order, but reduces the ability of the IDE to match the appropriate suggestion with the parameter when using code completion. Proper naming can help the IDE, but nothing is as helpful to an IDE as static compile-time checking that can be accomplished with these custom types. In general, I prefer to move as much automatic checking as I can from runtime to compile time and having these statically defined custom types rather than generic types accomplishes this.

Furthermore, the existence of these custom types makes it easier to add more details in the future. For example, I might add the full state name or other details about the states to that enum in the future without changing the interface. I could not have done that with a simple String representing state. An additional implied benefit of this is that even with these simple custom types I have more flexibility to change implementation without changing the interface. The custom classes (but not the enums) could be extended (the primitives and built-in String typically cannot) and I have flexibility to add other implementation details to the custom types that I cannot add to the built-in types.

Costs and Disadvantages

One of the most frequently cited disadvantages of the custom type approach is the overhead of extra instantiations and use of memory. For example, the Name class requires instantiation of the Name class itself AND its encapsulated String. However, it is my opinion that this argument is often made more from the perspective of premature optimization than a legitimate measured performance issue. There are situations in which the extra instantiations are too costly to justify the enhanced readability and compile-time checking, but many (perhaps most) situations can afford the extra instantiations with negligible observable impact. It is especially difficult for me to believe that use of a custom enum instead of a String or boolean will introduce a performance issue in the majority of cases.

Another argued downside of employing custom types rather than built-in types is the extra effort to write and test these custom types. However, as my examples in this post have shown, there are typically very simple classes or enums and are not difficult to write or test. With a good IDE and a good scripting language like Groovy, these are particularly easy to write and test, often automatically.

Conclusion

I like the use of custom types to improve readability and to shift more of the burden of parameter type checking onto the compiler. The biggest reason I don't use this approach by itself more in improving the readability of methods and constructors with very long parameter lists is that it doesn't, by itself, reduce the number of parameters. It makes the long list more readable and safer to use, but callers still must write clunky client-side code to invoke the method or constructor. Because of this, I often use techniques other than or in addition to custom types when improving a method accepting a long list of parameters. These other techniques will be explored in future posts.

Thứ Hai, 30 tháng 9, 2013

JavaOne 2013 Vicariously

I was disappointed that I was not able to attend JavaOne 2013, but was happy to see numerous useful posts covering this annual conference. In this post, I link to many of these resources and provide a brief summary of what each post discusses in relation to JavaOne 2013.

Keynotes

The keynotes are where the "big announcements" tend to occur. Fortunately, several online posts quoted key portions of the keynotes and provided different perspectives on what was said and the implications of the announcements. I group these references by order of my favorite keynotes at JavaOne: technical, strategy, and community.

JavaOne 2013 Technical Keynote

Java 2013 Strategy Keynote

JavaOne 2013 Community Keynote

Technical Sessions

Several blog posts have been written about specific technical presentation sessions, birds of a feather sessions, and hands-on lab sessions.

Overall Impressions and Summaries

This set of links is to posts summarizing the conference as a whole and relaying attendees' perspectives on the overall conference.

Kevin Farnham's (java.net) JavaOne 2013 Impressions

Kevin Farnham, managing editor at Java.net, has been posting his impressions from JavaOne 2013 in his editorials alongside the posts he references from Java.net.

Conclusion

This year's JavaOne appears to have continued many of the themes discussed at last year's JavaOne including GPUs, Raspberry Pi, Java SE 8 (especially lambda expressions), Java EE 7, NetBeans, OpenJDK, and JavaFX. Of course, there were new announcements related to these themes that included DukePad, open sourcing of Project Avatar, and new OpenJDK participants (Freescale, Linaro and Square)

Thứ Bảy, 21 tháng 9, 2013

My Favorite Books for Advanced Java Developers

The idea for my last blog post (my ten favorite online resources for advanced Java developers), was inspired by the Xiaoran Wang post Top 10 Websites for Advanced Level Java Developers. Wang also wrote a post called Top 10 Books For Advanced Level Java Developers. As with the post on best websites for advanced Java developers, it is easy to see why Wang listed the ten books he did list. In this post, I look at my top ten list which includes many of the same books as on his list, but my list has a few that are different.

There are numerous good (and some not so good) books aimed at beginning Java developers. However, it seems far more difficult to find good Java books for intermediate and advanced developers. There are plenty of books that provide in-depth coverage on very narrow topics and so are suitable for advanced Java developers, but there seems to be few "more general" Java books aimed at advanced developers.

5. Java Generics and Collections

I think many Java developers would say that using Java collections is easy and that using generics can range from easy to difficult depending on what you're doing. However, there is much in Java Generics and Collections (O'Reilly, 2006) to appeal to the advanced developer in its coverage of both generics and collections. The authors of this book point out useful practices related to generics as well as outlining which collections to use in different situations. Even some experienced Java developers may not always consider which collections to use in a particular situation as carefully as they should and this book provides insight into advantages and strengths of each major Java standard collection as well as the drawbacks of each. The book delves deeply into the quagmire of generics and outlines important considerations such as the get and put principle.

4. Java Performance

Charlie Hunt's and Binu John's Java Performance (Pearson Education, 2011) provides in-depth coverage regarding tuning of Java applications. The book outlines the many facets of performance tuning as it summarizes the command-line options that are available and how they can be used to measure and tweak settings so that applications will perform better. This is a complex topic that is covered thoroughly and with focus on recent versions of Java.

3. The Well-Grounded Java Developer

The Well-Grounded Java Developer (Manning, 2012) is a book that is definitely targeted at intermediate and advanced Java developers. As I discussed in my review of The Well-Grounded Java Developer, it helps experienced Java developers come up to speed on some of the latest Java and JVM trends (Java 7, dependency injection, Scala, Groovy, Clojure) while also covering some topics in depth that rarely receive that type of treatment (class loading, performance tuning, concurrency). There are books that specialize in each of these topics, but this is one book that can quickly provide a foundation in all of these advanced topics (and more) in a single book.

2. Java Concurrency in Practice

Like generics, concurrency is another skill that even many advanced Java developers can afford to enhance. Java Concurrency in Practice (Pearson Education, 2006, by Brian Goetz and a host of other Java concurrency luminaries) is the de facto standard among Java books for coverage of writing concurrent applications in Java.

1. Effective Java

Both editions (First Edition and Second Edition) of Effective Java (Joshua Bloch, Pearson Education, Second Edition, 2008) have been outstanding. Christian Beutenmüller made a good point on the DZone syndicated version of Ryan Wang's Top 10 Books for Advanced-level Java Developers: "I would remove Effective Java (since this is one of the first books I recommend to beginners)." Like Beutenmüller, I too recommend Effective Java to new Java developers, but I find myself referring even intermediate and advanced Java developers to Effective Java and refer to it regularly. There are portions of Effective Java that are easily digestible even by those relatively new to Java and then there are portions of that book that I've realized that I don't really appreciate until I have gained knowledge and experience. In many cases, I need realistic experience doing something the wrong way to understand some of the benefits and nuances of the practices outlined in this book. In short, Effective Java is one of the few books I can think of that is particularly appropriate to beginning Java developers, particularly appropriate to intermediate Java developers, and particularly appropriate to advanced Java developers.

Honorable Mention

There are other books that could have made this list and most of us probably have different takes on what are advanced Java books. For me, an "advanced Java developer" is a Java developer with significant depth of knowledge, significant breadth of knowledge, awareness of new and upcoming features of Java, and awareness of tools and products in the Java community that aid the entire Java development lifecycle. Effective Unit Testing and Java Power Tools are two books that are not on advanced subjects, but are books that I think contain information that can help a Java developer move from being a beginner to an intermediate or advanced Java developer. In particular, Effective Unit Testing can help Java developers write better and more efficient unit tests and Java Power Tools helps Java developers increase their breadth of knowledge key open source tools that can be used in all phases of Java development. Beginning Java developers tend not to have the unit testing experience that is contained in Effective Unit Testing and generally lack knowledge of the products available to the Java developer as outlined in Java Power Tools.

Conclusion

It is my belief that it is difficult to write and publish an advanced Java book. Writing an advanced Java books requires the author(s) to have deep understanding of the topic being written about and it is likely that publishers generally sell far more introductory books than advanced books. The barrier to entry seems much higher for writing and publishing advanced Java books as compared to writing and publishing entry-level Java books. Online resources in many ways seem better suited for satisfying advanced Java developers, but the five books I listed in this post buck that trend and provide a level of detailed and thorough information unmatched in the online resources in terms of accessibility and cohesiveness. The books in this list are useful to advanced Java developers, but are probably most useful in helping Java developers to become advanced Java developers.

Thứ Hai, 16 tháng 9, 2013

My Favorite Online Resources for Advanced Java Developers

The ProgramCreek.com blog has recently featured two interesting posts targeted at "advanced" Java developers: Top 10 Books For Advanced Level Java Developers and Top 10 Websites for Advanced Level Java Developers. These posts highlight resources that are especially beneficial to more experienced Java developers. I generally cannot argue with the lists as all the resources listed are useful to Java developers, but if I had to choose my top ten books and top ten online resources for advanced Java developers, there would be a few differences. In this post, I look at some of those differences in my list of best online resources for advanced and intermediate Java developers.

Many of the online resources on my list of best online resources for intermediate and advanced Java developers are the same as listed on the Xiaoran Wang's blog post Top 10 Websites for Advanced Level Java Developers. However, before reading that post, I was not aware of (and so have not had a chance to experience myself) two of them: LeetCode.com and Coursera. Although Wang also has had some interesting posts on ProgramCreek.com, I probably would not have had that site on my list, but it is not surprising he would list his own site on his list. I really like Wikipedia, but rarely use it related to software that I'm developing. Taking out those four sites, my top ten sites for advanced Java developers are as follows.

10. Google News on Java

One easy way to learn about the latest developments in Java (something often of more value to experienced Java developers than those beginning to use Java) is to search Google News for Java.

9. Javit - Reddit/Java

The Javit (Reddit/Java) site does not have as many new articles and blogs referenced as other social media Java-oriented sites like JavaLobby and StackOverflow, but it seems to often link to a very different set of posts and articles than the other sites. I don't check it as often as the others, but I do find an occasional perusal of its links to be worth my time to learn something new about the Java ecosystem.

8. Java Code Geeks

The Java Code Geeks site is a site that includes some original Java-oriented articles and posts in addition to a plethora of syndicated posts created by JCG partners. Several socially-oriented sites are on my list and many of the same articles and posts are featured on multiple of these socially-oriented sites, but each does have some differently featured posts than others.

7. Oracle Technology Network for Java Developers and Java Magazine

Oracle Technology Network (OTN) includes a Java section that features original Java-themed articles, Java news and announcements, references to other Oracle documentation, and links to Java-oriented blogs written by Oracle employees. Some of the employees' blogs that I've found most useful in terms of advanced Java concepts (advanced meaning complex or new) include Joseph D. Darcy's Oracle Weblog, Brian Goetz's Oracle Blog, Mark Reinhold's There's Not A Moment to Lose!, The Java Source, and Geertjan's Blog (which occasionally discusses NetBeans).

Java articles used to have to share space and focus with Oracle database and other products in Oracle Magazine. Today, Java gets its own electronic magazine in Java Magazine, published every two months. The articles in this online magazine are often heavy on newer topics and more advanced topics and so are especially well suited to experienced Java developers.

6. IBM developerWorks

I have found numerous useful articles and presentations for advanced Java developers on IBM developerWorks, which includes a Java emphasis. Authors of articles on this site include Brian Goetz, Elliotte Rusty Harold, Kelvin Lawrence, Ted Neward, and Neal Ford. Speaking of Neal Ford, his IBM developerWorks series on Java.next is a great example of the types of articles that will often appeal to advanced Java developers. IBM developerWorks has published in-depth (in addition to introductory) Java-oriented articles for many years and so now provides a nice mix of both the new and the historically useful.

5. JavaWorld

JavaWorld has been around for a long time and one of the advantages of this is the rich archive of detailed articles written against many different major releases of Java. JavaWorld has evolved somewhat over the years and currently provides a mix of original content with syndicated blog posts and syndicated versions of articles published by sibling publications such as InfoWorld.

4. DZone/JavaLobby

DZone.com is interesting from a general software development perspective and its "Java Zone" JavaLobby.com is interesting from a more Java-specific frame of reference. Both the more general DZone and the more specific JavaLobby link to articles and blogs submitted by "the community." Because the same community votes up or down and can leave comments on the posts, there can be strong community endorsement of good resources, warning to avoid spam or less valuable resources, and comments exchanged that add to the value of the referenced posts. Often, I've found the comments on the DZone syndicated versions of post to be better and more interesting than those of the original article referenced on DZone. As an example of this, the DZone-syndicated version of Top 10 Books for Advanced-level Java Developers has more comments than the original post as of this writing.

3. java.net

The java.net site is another on which I browse headlines on nearly a daily basis during the work week. There are a wide variety of referenced blogs and articles as well as polls on topics of interest to Java developers and editorials on Java-related topics. It's a nice single site to quickly gauge the current events in the world of Java.

2. stackoverflow.com

I doubt there are many Java developers who don't appreciate stackoverflow.com on a regular basis. Although the web in general has changed the way we write, maintain, and debug code, stackoverlow.com has been one of the biggest examples of how things have changed. Software development knowledge was formerly traded purely in conversations, books, articles, and conferences. Then, the advent of the Internet brought forth forums and usergroups for sharing software development knowledge and tactics. The rise of powerful search engines made it much easier to find what one was looking for.

The stackoverflow.com site has made things better than ever for the social collaboration among Java developers, making it easy to locate multiple solutions to multiple problems with community discussion about the merits and disadvantages of each approach. I find this valuable because I rarely need to go to the web for "easy" stuff; I typically go there for strange error messages or little known issues and stackoveflow.com meets that need. The ProgramCreek.com post summarizes it nicely: "Stackoverflow.com is probably the most popular website in the programming world." There is good reason for this.

1. Oracle's Java SE and EE Documentation and OpenJDK Documentation

By Java SE and EE documentation, I mean the following:

The OpenJDK documentation is useful in a similar fashion to how the Oracle Java SE and Java EE documentation is useful. The OpenJDK documentation is particularly useful for learning about new releases of Java such as JDK 8. Significant features of each release are briefly summarized with links to significantly more detail. Examples of this are Project Lambda and Project Jigsaw. Being able to look at source code is illustrative and helps a Java developer become more skilled as well.

Honorable Mention

There are several other useful online resources for improving one's Java abilities even when already fairly experienced in Java. One such example is the Java Specialists Newsletter. Other examples include some blogs that seem to focus on advanced Java topics such as Peter Lawrey's Vanilla #Java.

Conclusion

In many ways, software development is easier than it's ever been with the ability to find useful hints, tips, and answers to questions online with powerful search engines and using social media that helps target answers that tend to be more accurate. These resources have allowed us to expend energy and effort in other creative efforts in software development. In this blog post, I have looked at my top ten online resources for continuing to learn Java even after working with the language and platform for many years. Many forums have questions (and answers) that point newcomers to Java to appropriate beginner materials. I liked Wang's post on online resources for more advanced Java developers and have used this blog post to share my own (slightly different) list of good online resources for more advanced Java developers.