Java Records

A couple of days ago Java 16 was officially released and the latest incarnation promoted some preview features to general availability, as well as including a number of JVM updates and improvements. The one new feature that I really like is Java Records. This is a way to quickly and easily create immutable container classes using less code.

Java Record

Creating a record is as simple as…

record Point ( int x, int y ) {
}

The advantages of this is the compiler will provide getters, equals(), hashCode() and toString() methods for free without the need to explicitly added them. The result is less code and a nice clean immutable class with no clutter.

Form this simple line of code, the compiler will give you;

  • Getter accessor methods
  • toString()
  • equals()
  • hashCode()

Example using the ‘compiler provided’ record methods

public static void main( final String args[] ) {
    Point point = new Point( 10, 20 );

    // Use the provided methods from the new record
    System.out.println( point.x() + ", " + point.y() );
    System.out.println( point.toString() );

    System.out.println( point.equals( new Point( 10, 20 ) ) );
    System.out.println( point.hashCode() );
}

Override the Constructor

The compiler will generate a special constructor for the record, this is a it different from a regular class constructor. The compiler will assign the supplied arguments to private fields. Should you need to add some custom logic in the constructor, this is possible.

record Person( String name, int age ) {
    if( age < 0 ) {
        throw new IllegalArgumentException( "Age cannot be negative" );
}

Support for JSON

The library jackson-databind version 2.12.2 has just been released to provide support to serialise and deserialise records.

No need to add or anything or decorate the record. Example usage…

ObjectMapper objectMapper = new ObjectMapper();

Point point = new Point( 10, 20 );

String pointJson = objectMapper.writeValueAsString( point );
System.out.println( pointJson );

Point newPointFromJson = objectMapper.readValue( pointJson, Point.class );
System.out.println( "New Point: " +  newPointFromJson );

JSON Annotations

Optional annotations can be added to change the field names…

record Point ( @JsonProperty( "pointX" ) int x, @JsonProperty( "pointY" ) int y) {
}

Summary

I really like this feature, write less code and get more. Immutable objects should always be favoured where possible. Although the IDE can auto generate the same code, the class is cluttered and it’s all to easy to add unnecessary setters breaking immutably.

Advantages

  • Less code leads to cleaner, uncluttered classes
  • Removes need to unit test boiler plate e.g. getters etc
  • Provides toString(), hashCode() and equals() methods
  • Encourages the creation of immutable objects by default