June 17, 2026 in code-smells5 minutes
A intermediate-level guide to Long Parameter List: before-and-after java code and diagrams for a CS student.
Imagine you are reviewing a colleague’s pull request. You see a method call that looks like a series of disconnected numbers and booleans. Without looking at the method definition, it is impossible to tell what each value represents or in what order they should appear.
public class ShippingService {
// High cognitive load: hard to tell which int is width vs height
// Easy to swap arguments by mistake without compiler error
public double calculateShipping(double weight, double length, double width, double height,
String destinationZip, boolean isExpress)
return (weight * 0.5) + (length * width * height * 0.1) + (isExpress ? 10.0 : 0.0);
public static void main(String[] args) {
ShippingService service = new ShippingService();
// Is this length=10, width=5 or vice versa?
double cost = service.calculateShipping(2.5, 10.0, 5.0, 8.0, "90210", true);
}
}This code suffers from high cognitive load. As the developer, you have to manually map 10.0 to length and 5.0 to width by jumping back and forth between the call site and the method signature. Even worse, because many of these parameters share the same type—like double or int—the compiler cannot help you if you make a mistake. If you accidentally swap length and width, the program will still run perfectly, but your shipping calculations will be silently wrong.
classDiagram
class ShippingService {
+calculateShipping(double weight, double length, double width, double height, String destinationZip, boolean isExpress) double
}
A “Long Parameter List” is a code smell that occurs when a method requires too many arguments to perform its task. This often happens when we pass around several primitive types that are logically related but haven’t been grouped together.
You should watch for these red flags:
double or int).width, height, length) being passed together across multiple different methods in your system.
flowchart TD
A[Method Call] --> B{Are there many parameters?}
B -- Yes --> C{Are they mostly primitives?}
C -- Yes --> D[Long Parameter List Smell]
C -- No --> E[Consider different refactorings]
B -- No --> F[Code is likely fine]
To fix this, we use the Introduce Parameter Object refactoring. We take that “clump” of related data and wrap it into its own class or record. This turns a list of loose variables into a single, meaningful object.
public record PackageDimensions(double length, double width, double height) {}
public record ShippingDetails(
double weight,
PackageDimensions dimensions,
String destinationZip,
boolean isExpress
) {}
public class ShippingService {
// Parameters are now grouped into meaningful objects (Parameter Objects)
// This prevents accidental swapping of dimension values
public double calculateShipping(ShippingDetails details) {
double vol = details.dimensions().length() *
details.dimensions().width() *
details.dimensions().height();
return (details.weight() * 0.5) + (vol * 0.1) + (details.isExpress() ? 10.0 : 0.0);
}
public static void main(String[] args) {
ShippingService service = new ShippingService();
PackageDimensions dims = new PackageDimensions(10.0, 5.0, 8.0);
ShippingDetails details = new ShippingDetails(2.5, dims, "90210", true);
double cost = service.calculateShipping(details);
}
}By grouping dimensions into PackageDimensions and combining everything into ShippingDetails, we have gained two major advantages:
details.dimensions(), the purpose of those values is immediately obvious.weight where a length belongs because they are now encapsulated within distinct types.
classDiagram
class ShippingService {
+calculateShipping(ShippingDetails details) double
}
class ShippingDetails {
double weight
PackageDimensions dimensions
String destinationZip
boolean isExpress
}
class PackageDimensions {
double length
double width
double height
}
ShippingService ..> ShippingDetails : uses
ShippingDetails *-- PackageDimensions : owns
The following sequence shows how the ShippingService interacts with these new objects to perform its calculation:
sequenceDiagram
participant S as ShippingService
participant D as ShippingDetails
participant P as PackageDimensions
S ->> D: weight()
D -->> S: weight
S ->> D: dimensions()
D -->> S: dimensions
S ->> P: length()
P -->> S: length
S ->> P: width()
P -->> S: width
S ->> P: height()
P -->> S: height
S ->> D: isExpress()
D -->> S: isExpress
While introducing parameter objects solves the problem of long lists, it is not a silver bullet.
Use it when:
latitude and longitude, or width, height, and depth).Avoid it if:
Map<String, Object>. While a Map can hold any number of arguments, you lose all type safety. You’ll have to cast every value back to its original type, which is prone to runtime errors and defeats the purpose of using Java.The refactored call is more verbose but significantly clearer and type-safe.
service.calculateShipping(new ShippingDetails(2.5, new PackageDimensions(10, 5, 8), "90210", true));