A new type called a “record” was previewed in Java 14 and released in Java 16. One of the benefits is that it creates immutable objects. Kind of.
An immutable record
This is record is an immutable object. Since it is a record, it is automatically final and has no setters. All is good.
public record Book (String title, int numPages) { }
A mutable record
There there is this record. Do you see why it is mutable?
public record Book (String title, int numPages, List<String> chapters) { }
The problem is that records use shallow immutability. The caller can’t change the “chapters” object to a different reference. The caller can change the values in the “chapters” to their heart’s content. That means this object is still mutable.
Here’s an example showing that the code prints [1, 2, 3] and therefore changes the list of chapters.
List<String> chapters = new ArrayList<>();
chapters.add("1");
Book book = new Book("Breaking and entering", 289, chapters);
chapters.add("2");
book.chapters().add("3");
System.out.println(book.chapters());
Making the record actually be immutable
It’s pretty easy to make the Book record actually be immutable. In fact, it only requires three extra lines! Records have a compact constructor which takes care of the setting fields for you. However, you can choose to change that behavior. In this example, I rely on the default set of “title” and “numPages”. However, for “chapters”, I choose to make an immutable copy to prevent changing the list.
public record Book (String title, int numPages, List<String> chapters) {
public Book {
chapters = List.copyOf(chapters);
}
}
Now the test program fails with an UnsupportedOperationException. Much better. A real immutable record.
>Making the record actually be mutable
Seems to be misprint – “actually immutable” supposed?
And unfortunately this does not make record truly immutable – original chapters variable may be modified after record creation and record will be changed.
@isopov Good point. Fixed both. Using List.copyOf now
You should use List chapters
as parameter so it would not allow you to add new chapters but you could read the chapters.
Exposing mutable state is dangerous.
Agree. Hence the need to code carefully
And remember to ake an immutable copy.
Another option would be to use an Immutable List implementation like https://www.javadoc.io/static/io.vavr/vavr/0.10.4/index.html?io/vavr/collection/List.html
Sure. But a built in API meets needs in this case.