This is mostly a matter of preference. Using chaining tends to create more readable code, and can actually reduce CPU/heap memory. For example, consider these two snippets of code:
// No chaining
KeyPair kp = new KeyPair();
kp.setKey(key);
kp.setValue(value);
Utils.someMethod(kp);
// Chaining
Utils.someMethod(new KeyPair().setKey(key).setValue(value));
With chaining, we've turned four lines of code into just 1, and removed a temporary variable that was only used to hold data long enough to set the values. I commonly use this pattern to build custom exceptions that can throw additional information:
throw new CustomException().withValue(value);
This pattern is more frequently found with classes that have a ton of optional parameters where only a few will be set. This can drastically reduce the number of times a single function has to be written. For example, imagine you had a class like this:
class SomeClass {
SomeClass(Object value1) {
...
}
SomeClass(Object value1, Object value2) {
...
}
SomeClass(Object value1, Object value2, Object value3) {
...
}
...
SomeClass(Object value1, Object value2, Object value3, Object value4, Object value5, Object value6, Object value7, Object value8, Object value9, Object value10...) {
...
}
}
When there's a ton of optional parameters available, mistakes tend to be made. A function that accepts 32 parameters, many of them optional, can be a nightmare to manage. For example, consider these two pieces of code:
Utils.someFunction(null, null, null, null, null, null, null, null, 5, null, null, null, null, null, null, 2, null, null, 'Hello World');
Utils.someFunction(new Parameter().setParam9(5).setParam16(2).setParam19('Hello World'));
Which one do you think is easier to read? Which is easier to maintain? Not only do you know what values you're assigning, you also get the option to order them any way you want to:
Utils.someFunction(new Parameter().setParam16(2).setParam9(5).setParam19('Hello World'));
This can reduce the SomeClass
complexity, and large functions that can have an arbitrarily large number of parameters can be reduced to a far more readable form. This also essentially lets us have named parameters, much like Ruby, C#, and other advanced languages.
However, you shouldn't use this everywhere. Use chaining when it makes sense, but don't return values that will never be used. This only clutters your code and makes it more confusing in the long run, and does marginally increase CPU usage (it's faster to not return a value at all than it is to return a chainable object).
As @KeithC pointed out by way of the link (Builder Pattern: Good for code, great for tests), this also lets you build objects that have a ton of default values but can then be customized. The code mentioned there is Java, but also easily applies to Apex Code as well. In fact, I'll borrow one of their examples to demonstrate:
Account account = new AccountBuilder()
.withId(1)
.withName("test")
.withBalance(10)
.build();
Using builders lets you set a bunch of default values (maybe record types, required fields, etc), as well as providing customization. In fact, this AccountBuilder
class could easily be a legitimate piece of Apex Code. You could easily build records for unit tests with default values, and customize each account to a specific unit test. Of course, these exact functions may not make sense in your organization's case, but it demonstrates how you could build standard records with default values and optional customizations.