Friday, February 19, 2021

Compact constructor for Record classes

Consider a scenario where we wanted to validate the parameter before constructing the object. 

In our Cat record class example, we wanted to validate the color parameter before allowed an instance of Cat to be created. 

We can have a canonical constructor for our Cat record, in which we include the validation. Code for this shown below

record Cat(String color) {
    Cat(String color) {
        if (color.matches(".*\\d.*")) {
            throw new IllegalArgumentException("Invalid color");
        }
        this.color = color;
    }
}

Here, we validate the color parameter in the constructor to check if it contains any numeric character in it. 

And if it does, we throw an IllegalArgumentException. Otherwise we proceed to complete the creation of the object by assigning the color to auto-generated instance variable.

Note however that there is repetition of the parameter list - one at the record header and again the same list is repeated in the constructor. 

This can be avoided by using a compact form of constructor declaration supported for record classes. 

Below is the same code with compact constructor

record Cat(String color) {
    Cat {
        if (color.matches("*\\d*")) {
            throw new IllegalArgumentException("Invalid color");
        }
    }
}

The parameter list for compact constructor is implicit, and is the same as that of component list in record definition. 

Also note the missing assignment statement in the compact constructor form

this.color = color;

This again is implicit, all implicit parameters gets assigned to their corresponding instance variables. 

Another question is at what point in time is this assignment done? 

Well, its done at the end of the constructor, after all the custom validation code in the compact constructor is executed. To illustrate this, consider the following code 

record Cat(String color) {
    Cat {
        if (this.color.matches("*\\d*")) {
            throw new IllegalArgumentException("Invalid color");
        }
    }
}

Here we try to use this.color in our validation logic. 

This code fails to compile, throwing an error "variable color might not have been initialized", indicating that the parameter assignment to instance variables happens at the end of construtor.


Sample code used in this post can be downloaded from https://github.com/ashokkumarta/awesomely-java/tree/main/2021/02/Language-Features/Record/Compact-constructor

No comments:

Post a Comment