Records as a logical conclusion of Immutable Classes
Tags: java, backend, designpatterns, coding
Published: 2023-05-02 15:08:23

`Record` type is an addition to **Java 17**, which has some features that help us when we code and are useful when we're thinking about whether a new class should have setters, or factory methods.

In Joshua Bloch's book **Effective Java** he writes about the importance of immutable classes since it is not necessary for most of us to create classes with setters. He said: 

> An (...) advantage of static factory methods is that, unlike constructors, they are not forced to create a new object each time they are called. This allows immutable classes to use pre-constructed instances, or to cache instances as they’re constructed, and dispense them repeatedly to avoid creating unnecessary duplicate objects.

We can see an example of misuse a mutable class, with setters, below:
First we create the typical `Car` class:

```java
public class Car {

    private String name;
    private String model;

    public String getName() {
        return name;
    }

    public String getModel(){
        return model;
    }

    public void setName(String name){
        this.name = name;
    }

    public void setModel(String model) {
        this.model = model;
    }
}
```
Next we create the main class that instatiates the `Car` class:

```java
public class CarFactory {
    public static void main(String[] args) {
        Car hondaCivic = new Car();
        hondaCivic.setName("Honda");
        hondaCivic.setModel("Civic");
        
        System.out.println("Car name" + hondaCivic.getName());
        System.out.println("Car model" + hondaCivic.getModel());
    }
}
```
Here is the output:

```
Car name: Honda
Car model: Civic
```
Although it looks good, there is a security flaw in this code, because even though the object name is `hondaCivic` and we set the corresponding parameters, we can change the values and get an invalid result. For example:

```java
public class CarFactory {
    public static void main(String[] args) {
        Car hondaCivic = new Car();
        hondaCivic.setName("Honda");
        hondaCivic.setModel("Civic");
        
        System.out.println("Car name: " + hondaCivic.getName());
        System.out.println("Car model: " + hondaCivic.getModel());

        hondaCivic.setName("Toyota");
        hondaCivic.setModel("Corolla");

        System.out.println("Car name: " + hondaCivic.getName());
        System.out.println("Car model: " + hondaCivic.getModel());
    }
}
```
Here is the output, in which we can see a logical malfunction:

```
Car name: Honda
Car model: Civic
Car name: Toyota
Car model: Corolla
```
`hondaCivic` is an object created from a mutable class, which means that after it is created, we can change the properties (or attributes) of the object. This is not bad by itself, but in large applications it can be very complex when dealing with these types of classes. 

The alternative of mutable classes are, of course, immutable classes. This means that, when instantiated, this object represents the same collection of properties all the time. 

The are many forms of creating immutable classes, here is a very simple one, by changing the `Car` class:

```java
public class Car {

    // The default constructor is private
    // preventing multiple instantiation
    private Car () {}

    private String name;
    private String model;

    public String getName() {
        return name;
    }

    public String getModel(){
        return model;
    }

    // A static method who return the desired 
    // car object
    public static Car createHondaCivic(){
        Car car = new Car();
        car.setName("Honda");
        car.setModel("Civic");

        return car;
    }

    public static Car createToyotaCorolla(){
        Car car = new Car();
        car.setName("Toyota");
        car.setModel("Corolla");

        return car;
    }

    // There is no need of public setters anymore
    private void setName(String name){
        this.name = name;
    }

    private void setModel(String model) {
        this.model = model;
    }
}
```
As we said erlier, instead of letting `CarFactory` set any type of properties, or create any intance with mutable condition, we restrict it to only two types of `Car`. Remmember that this is a very simple example. We can use this pattern without any problem, but we'll see a more flexible one later. 

Next, we'll look the refactored `CarFactory` class:

```java
public class CarFactory {
    public static void main(String[] args) {
        Car hondaCivic = Car.createHondaCivic();
        
        System.out.println("Car name: " + hondaCivic.getName());
        System.out.println("Car model: " + hondaCivic.getModel());

        Car toyotaCorolla = Car.createToyotaCorolla();

        System.out.println("Car name: " + toyotaCorolla.getName());
        System.out.println("Car model: " + toyotaCorolla.getModel());
    }
}
```
Do we need a Honda Civic object? We use the `createHondaCivic()` method. Do we need a Toyota Corolla object? We use the `createToyotaCorolla()` method. As we said, this pattern is useful in some cases. 

But what happen if we need to set the properties of `Car` at runtime. Or if we simply need to set some of these properties from another class? It is a headache to create static methods inside the `Car` class every time we need a new type of properties of this class. And it's imposible (without reflection) if we need to do this at runtime. Then we will make another modification to the `Car` class:

```java
public class Car {

    private Car () {}

    private String name;
    private String model;

    public String getName() {
        return name;
    }

    public String getModel(){
        return model;
    }

    // Using one static method to set properties    
    public static Car createCar(String name, String model){
        Car car = new Car();
        car.setName(name);
        car.setModel(model);

        return car;
    }

    private void setName(String name){
        this.name = name;
    }

    private void setModel(String model) {
        this.model = model;
    }
}
```
Here we use the static method `createCar()` to get an immutable class. We can test this in `CarFactory`:

```java
public class CarFactory {
    public static void main(String[] args) {
        Car hondaCivic = Car.createCar("Honda", "Civic");
        
        System.out.println("Car name: " + hondaCivic.getName());
        System.out.println("Car model: " + hondaCivic.getModel());

        Car toyotaCorolla = Car.createCar("Toyota", "Corolla");

        System.out.println("Car name: " + toyotaCorolla.getName());
        System.out.println("Car model: " + toyotaCorolla.getModel());
    }
}
```
Remember, the output is the same:

```
Car name: Honda
Car model: Civic
Car name: Toyota
Car model: Corolla
```
Now we can have all the power of an immutable class, where no one can change the properties of the objects after instantiation. This is called **Singleton** pattern when:

- The default constructor is private, which prevents it from being accessed outside of the class
- No public setters, which prevent changing properties after instantiation
- Instantiation is handled by a static method, which returns an immutable object

There is the **Builder** pattern where the name of the properties are explicit at instantiation time. But this is out of the scope of this article. Although it is good that you to look for more information about it. 

Ok, but what is a `record` and what is its connection to immutable clases? Well, the thing is that since **Java 17** we can create a `record` like this:
```java
record Car(String name, String model){}
```
Record's properties are immutable. That means you don't need to create a private constructor and then create a static method to set values. You can instantiate the new `Car` ~~class~~ `record` below:
```java
public class CarFactory {
    public static void main(String[] args) {
        Car hondaCivic = Car("Honda", "Civic");
        
        System.out.println("Car name: " + hondaCivic.name());
        System.out.println("Car model: " + hondaCivic.model());

        Car toyotaCorolla = Car("Toyota", "Corolla");

        System.out.println("Car name: " + toyotaCorolla.name());
        System.out.println("Car model: " + toyotaCorolla.model());
    }
}
```
The output is the same as before, with immutable objects but with less code. 

This is an example of how a versatile design pattern can inspire design changes in a programming language like **Java**.