Custom Compact constructor in Record

In this post under Java Record, I will explain with example what is custom compact constructor, what is the use and how to add them in Record.

In the previous post under Java Record, I showed what is canonical constructor, what is custom canonical constructor and what is the purpose of it.

Below are the points for recap
1) For a Record, Java compiler adds a canonical constructor internally
2) Canonical constructor takes number of arguments equivalent to number of its fields and equivalent to fields data type, and initialize its fields using arguments values.
3) So basically canonical constructor initialize the record fields using input constructor arguments. It doesn’t do anything.
4) If you want to do input validation or input transformation before initialization you cannot do it.
5) That is where custom canonical constructor comes into picture. It lets you perform input validation or input transformation before initialization.

Below is an example of canonical constructor created by Java Compiler for a record named “Account”

Account

package core.record.package4;
public record Account(int id, String name, long amount) {
}

If you run the below command

javap -p Account.class

You will get the below output

Canonical constructor added by compiler

Compiled from "Account.java"
public final class core.record.package4.Account extends java.lang.Record {
private final int id;
private final java.lang.String name;
private final long amount;
public core.record.package4.Account(int, java.lang.String, long);
public final java.lang.String toString();
public final int hashCode();
public final boolean equals(java.lang.Object);
public int id();
public java.lang.String name();
public long amount();
}

In the above output, at line 6, you can see canonical constructor added by Java compiler

We can add our own custom canonical constructor as shown below

Custom Canonical Constructor

package core.record;
public record Account(int id, String name, long amount) {
public Account(int id, String name, long amount) {
if(amount < 500) {
throw new IllegalArgumentException("Amount less than 500");
}
this.id = id;
this.name = name;
this.amount = amount;
}
}

As you can see from the above code, we have to do what java default canonical constructor would do i.e., declaring constructor arguments, taking arguments values and initializating the fields in addition
to input validation.

We added custom canonical constructor to perform input validation but we also end up doing the job of java default canonical constructor.

So basically we implemented our business requirement and also the job of default canonical constructor provided by java compiler.

Custom Compact constructor lets us focus only on business requirement, whereas the field initialization is done by java compiler internally as show below

Custom Compact constructor

package core.record.package4;
public record Account(int id, String name, long amount) {
public Account {
if(amount < 500) {
throw new IllegalArgumentException("Amount less than 500");
}
}
}

As you can see from the above code, we only focused on implementing the validation and ignored argument declaration and field initialization, which is taken care by java compiler internally.

In this way we can use custom compact constructor.

Leave a comment