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.

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.

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.

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.

Dustin Marx is a principal software engineer and architect at Raytheon Company. His previous published work for JavaWorld includes Java and Flex articles and "More JSP best practices" (July 2003) and "JSP Best Practices" (November 2001).