FunctionFellows
3 min readJun 11, 2024

Java records were introduced in JDK 14 as a preview and released in JDK 16. The purpose of the Record is to provide an object-oriented way of creating a simple data carrier object.

Basic syntax

Record is a new type of class. An example of a record can look like this.

record Container(String name, int volume){
}

public record User(String firstName,
String lastName,
String emailAddress,
int age) {
}

As you see, it differs from a standard class definition. It has a header that lists arguments which define the data fields of the record.

The fields defined in the header will get implicit accessors. In opposition to the bean standards, implicit accessors of a record will not have a ‘get’ prefix. Therefore, to access the fields, you must use the name of a field as a method call, as presented below.

public class JavaRecordExample {
void method() {
var container = new Container("box", 32);
System.out.println(container.name());
}
}

record Container(String name, int volume) {
}

In addition to the Accessors record, it also implicitly implements methods equals(Object obj), hashCode(), and toString().

Constructor

The record's default constructor is different from a class's default constructor. The default constructor of the record assigns all the fields.

You can define the constructor explicitly, but it must assign the fields defined in the header. Below is an example of this.

record Container(String name, int volume) {
Container(String name, int volume) {
System.out.println("Some fancy stuff!");

this.name = "Some fancy name";
this.volume = volume;
}
}

You can also call the default constructor to assign some values, the same as you would in the case of a standard class.

 record Container(String name, int volume) {
Container(){
this("", 0);
System.out.println("Some fancy stuff!");
}
}

Note. Same as in the case of a constructor of a regular class, a call to another constructor must be the first statement.

If you only want to assign the fields as they are in the parameters of the constructor, but still need some custom behaviour in the constructor, you can use a compact constructor.

record Container(String name, int volume) {
Container {
System.out.println("Some fancy stuff!");
}
}

In the above example, the assignment statement of the name and volume fields is implicitly inserted at the beginning of the constructor.

Restrictions of the record

The Record has a couple of restrictions:

  1. Fields of the record are final, making the record immutable.
  2. The record itself is implicitly final.
  3. The record can not explicitly extend any object. (But can implement an interface).
  4. The record can not have any native methods.
  5. The record can not be abstract.
  6. Can not have instance fields other than declared in the header.
  7. Can not customize Serialization process by declaring writeObject and readObject methods.

Nested Records

Records can be nested, the same as any other class, but the nested record class is implicitly static. The same goes for the local record class (A record nested within a method). That results in the record not having access to anything from the enclosing method. That is because even if the enclosing method is static, its local variables are not.

The below code will not compile, and the error will be: Non-static variable ‘container’ cannot be referenced from a static context.


public class JavaRecordExample {
void method() {
var container = new Container("box", 32);
record InnerRecord() {
String method() {
return container.name();
}
}
}
}

For comparison, doing the same, but with the class, will work fine.

public class JavaRecordExample {
void method() {
var container = new Container("box", 32);
class InnerClass {
String method() {
return container.name();
}
}
}
}

The record can access other static content, as demonstrated below. The following code will compile fine.

public class JavaRecordExample {
static Container container = new Container("box", 32);
private void method() {
record InnerRecord(int a, int b) {
String method() {
return container.name();
}
}
}
}

Conclusion

The record class gives a perfect way to define a data structure. The restrictions enforced on the record make it so that you can rely on what data the record contains.