The Java 8 Streams API lends itself towards writing code functionally, rather than imperatively. As we know immutability offers many benefits and as such, I try to make objects immutable wherever practical. In day-to-day programming, I find myself in a situation where I'd like to "set" a value. My objects are immutable though, so I need to create a new object and initialise the field in the constructor.
I use project Lombok, which provides annotations such as @Value
which essentially makes the object immutable. It also has @Builder
which uses the builder pattern to provide a builder for the immutable object, setting fields unmentioned in the fluent API to null
.
The @Builder
annotation has a field named toBuilder
, which, when set to true, provides the toBuilder()
method, which returns a builder populated with the fields from the object, where the developer can "set" values, call build()
and return a new object.
E.G. to create a List
of immutable objects with modified forename
fields, I'd do the following:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import lombok.Builder;
import lombok.Value;
public class SOExample {
@Value
@Builder(toBuilder = true)
private static class Person {
private final String forename;
private final String surname;
private final int age;
private final int heightInCm;
}
public static void main(String[] args) {
List<Person> people = Arrays.asList(Person.builder()
.forename("stack")
.surname("overflow")
.age(21)
.heightInCm(180)
.build());
people.stream()
.map(p -> p.toBuilder()
.forename("updatedForename")
.build())
.collect(Collectors.toList());
}
}
Without using Lombok, this would require a lot of boiler-plate code. In fact, I've looked at the generated code and it's neither small nor trivial. This leads me to question myself. How are others out there doing it? I worry I'm missing a trick.
Taking into consideration the description and example above, what is the best way of returning a copy of an immutable object with updated field(s) and how would it be used in the Streams API?
An immutable object cannot be modified after it was created. Immutable objects have two great advantages: Code based on immutable objects is clearer and likelier to be correct. Bugs involving unexpected changes simply can't occur.
Create a copy of the mutable object (i.e. via copy constructor, cloning, serialization/deserialization, etc.); never store the reference to the original mutable object. Never return the mutable object. If you must to, then return a copy of the object.
An immutable object cannot be modified. An immutable object can be garbage collected. An immutable object cannot be garbage collected. String is immutable.
How often do you find you're having to do this?
If you're doing this in place of having modifiable classes, then perhaps it's a sign that really immutability doesn't make sense for your type.
If you're not doing it all that regularly, then just generating a new one with the accessors (and modifications to values) from the original doesn't seem too bad; nor does the Builder
example you showed.
Person personA = ...
Person personB = new Person("updated", personA.getSurname(), personA.getAge(), ...);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With