DEV Community

Cover image for Java record compact constructors (steal back from ai)
Davor Hrg
Davor Hrg

Posted on

Java record compact constructors (steal back from ai)

First in the series #stealbackfromai

you need validation for record or default values ?

I was silly trying this to define default values in a record:

public static record SomeCounts(UUID id, Long v1, Long v2, Long v3){
    SomeCounts(UUID id, Long v1, Long v2, Long v2){
        this(id,
                v1== null ? 0l : v1,
                v2== null ? 0l : v2,
                v3== null ? 0l : v3
                );
    }
}
Enter fullscreen mode Exit fullscreen mode

It does not compile (Canonical constructor cannot delegate to another constructor). Turns out there is nicer and cleaner way already provided called compact constructor.

Compact constructors

Compact constructors in Java records provide a concise way to customize the canonical constructor (the default one matching the record's components) without repeating parameter names.

Syntax Basics
Declare it immediately after the record header, using just the record name in braces—no parameter list needed:

public static record SomeCounts(UUID id, Long v1, Long v2, Long v3){
    public SomeCounts{
        // id = id; //do not do this, just set values you want to change
        v1 = v1== null ? 0l : v1,
        v2 = v2== null ? 0l : v2,
        v3 = v3== null ? 0l : v3
        // Validation example: 
        //if (id == null) throw new IllegalArgumentException();
    }
}
Enter fullscreen mode Exit fullscreen mode

The compiler implicitly supplies parameters matching the fields and handles field assignments after your body executes.12

Execution Flow

  1. Your compact body runs first (for validation/normalization).
  2. Compiler auto-assigns parameters to final fields.
  3. Superclass Record constructor completes.

You can modify parameters (like null checks), throw exceptions, or print logs, but cannot assign fields directly (this.v1 = ... fails compilation).3

Key Benefits

  • Zero boilerplate: No need to write this.field = field; everywhere.
  • Immutable safety: Fields stay final; changes only affect incoming parameters before final assignment.
  • Canonical only: Applies to the main constructor; doesn't affect static factories or other overloads.

Common Patterns

Use Case Example Code
Null-to-default v1 = (v1 != null) ? v1 : 0L; 4
Range validation if (v3 < 0) throw new IllegalArgumentException(); 5
Normalization id = id.toString().toLowerCase(); 5

This keeps your record cleaner while ensuring numeric fields are never null post-construction.1678910

Do not set all fields

How Assignment Works
The compact constructor modifies local parameter variables, not fields directly. After your body executes, the compiler implicitly assigns each parameter to its corresponding final field, so those values that you do not change are set(I was defensive and setting all of them, but even).

If you declare an empty compact constructor, it will work just fine, no worries like for java beans.

public static record SomeCounts(UUID id, Long v1, Long v2, Long v3){
    public SomeCounts{
        // all values will be set, do not worry
    }
}
Enter fullscreen mode Exit fullscreen mode

  1. https://blogs.oracle.com/javamagazine/post/java-record-compact-canonical-constructor 

  2. https://docs.oracle.com/en/java/javase/16/language/records.html 

  3. https://stackoverflow.com/questions/74083123/java-record-compact-constructor-bytecode 

  4. https://xebia.com/blog/how-to-use-java-records/ 

  5. https://mikemybytes.com/2022/02/16/java-records-and-compact-constructors/ 

  6. https://www.reddit.com/r/java/comments/stte7o/java_records_compact_constructors/ 

  7. https://stackoverflow.com/questions/77582274/throw-exception-in-records-compact-constructor 

  8. https://www.baeldung.com/java-records-custom-constructor 

  9. https://coderanch.com/t/754107/certification/understand-Records-comapact-constructor-overloaded 

  10. https://www.youtube.com/watch?v=i0p1B7L3FW8 

Top comments (0)