You subclass Person into Employee. Ages for employees must sit between 18 and 67. You want to reject a bad age before calling super(...) — fail fast, no half-built superclass state.

For decades Java said no: the first statement had to be super(...) or this(...). So teams invented a private static helper and stuffed the check into the argument list.

Employee(String name, int age) {
    super(name, verifyAge(age)); // the hack
}

private static int verifyAge(int age) {
    if (age < 18 || age > 67)
        throw new IllegalArgumentException("age out of range: " + age);
    return age;
}

It works. It is also noisy and easy to miss when you skim the constructor.

Flexible constructor bodies let a constructor have a prologue (statements before super / this) and an epilogue (statements after). The prologue can validate arguments, prepare values for the next constructor, and assign this class’s fields — without treating the object as fully constructed.

The problem the old rule created

Two pain points show up again and again:

  1. Fail-fast validation — you want to throw before the superclass constructor runs, not after it has already allocated and initialized superclass fields.
  2. Subclass integrity — a superclass constructor that calls an overridable method can see subclass fields still at default (null, 0, false) because the subclass constructor has not run its assignments yet.

The static-helper pattern fixes (1) awkwardly. It does nothing for (2). Flexible constructor bodies address both.

When flexible constructor bodies shipped

ReleaseStatusSpec
Java 22Preview (“Statements before super()”)JEP 447
Java 23Second previewJEP 482
Java 24Third previewJEP 492
Java 25 LTSStandard featureJEP 513

Use Java 25+. No --enable-preview. The final feature matches the last preview — no API surprise at finalization.

Mental model: prologue and epilogue

SubclassCtor(...) {
    // prologue  — early construction context
    super(...);  // or this(...)
    // epilogue  — instance is usable as usual
}
PhaseWhen it runsWhat you can do
PrologueBefore super(...) / this(...)Validate args; compute values; assign this class’s fields that have no field initializer
EpilogueAfter that call returnsNormal constructor code: call instance methods, read fields, finish setup

If you omit an explicit super / this, the compiler still inserts super() at the start — the whole body is then epilogue, same as before.

Invocation order across a hierarchy: prologues run bottom-up, then epilogues run top-down. That is how a subclass can initialize its own fields before a superclass constructor body (or an override it calls) can observe them.

Lab: fail fast without the helper

Before (validation after super — wasteful if age is bad):

class Person {
    final String name;
    final int age;

    Person(String name, int age) {
        if (age < 0)
            throw new IllegalArgumentException("age");
        this.name = name;
        this.age = age;
    }
}

class Employee extends Person {
    Employee(String name, int age) {
        super(name, age); // runs even when age is 12
        if (age < 18 || age > 67)
            throw new IllegalArgumentException("age out of range: " + age);
    }
}

After (prologue validates, then delegates):

class Employee extends Person {
    Employee(String name, int age) {
        if (age < 18 || age > 67)
            throw new IllegalArgumentException("age out of range: " + age);
        super(name, age);
    }
}

No private static helper. The check sits where a reader expects it.

Lab: prepare arguments, then call super

When building the superclass args takes more than one expression:

class ColoredBox extends Box {
    ColoredBox(int width, int height, String colorName) {
        Objects.requireNonNull(colorName, "colorName");
        Color color = Color.decode(colorName); // prologue computation
        super(width, height, color);
    }
}

Anything you could have jammed into super(width, height, Color.decode(...)) can live as clear statements in the prologue — still without reading this as a finished object.

Lab: initialize subclass fields before super

When a superclass constructor calls an overridable method, subclass fields used to stay at defaults until after super returned. Assign them in the prologue instead:

class Person {
    final String name;

    Person(String name) {
        this.name = name;
        describe(); // may dispatch to subclass override
    }

    void describe() {
        System.out.println("Person " + name);
    }
}

class Employee extends Person {
    final String officeId;

    Employee(String name, String officeId) {
        Objects.requireNonNull(officeId, "officeId");
        this.officeId = officeId; // before super — field must lack an initializer
        super(name);
    }

    @Override
    void describe() {
        System.out.println("Employee " + name + " @ " + officeId);
    }
}

new Employee("Ada", "CAM-FORA") can now print a non-null office id from describe(), because the prologue ran first.

Note: Calling overridable methods from constructors is still a smell (Effective Java Item 19). Flexible bodies reduce the damage when a superclass already does it; they do not make the pattern good design. Prefer not to leak this from a constructor at all.

What the prologue cannot do

The prologue (and super / this argument lists) sit in an early construction context:

AllowedForbidden
Throw on bad argsreturn (with or without a value)
Call static methods / use localsCall instance methods on this
Assign fields declared in this class with no field initializerRead fields of this (including after you just assigned them, in ways that count as a read of the instance)
Compute values passed to super / thisAssign superclass fields; touch fields that already have = ... initializers

Rough rule: treat the prologue like “almost static,” with one exception — simple assignments to your own uninitialized fields.

When they win vs when to skip

NeedPrefer
Fail-fast checks before superPrologue if + throw
Non-trivial prep of super argsLocals in the prologue
Subclass fields visible if superclass code runs earlyAssign those fields in the prologue
Complex multi-step creationFactory or builder — not a mega-constructor
Shared setup across many ctorsthis(...) chaining; keep one canonical constructor

Do not turn every constructor into a mini-framework. Flexible bodies remove an artificial restriction; they do not invent a new place for business workflows.

Gotchas

Fields with initializers

You cannot assign this.x in the prologue if x already has a field initializer (int x = 0;). Drop the initializer and assign in the prologue, or assign in the epilogue after super.

Records

Record compact constructors are a different feature. Flexible constructor bodies apply to ordinary class (and enum) constructors. Keep records for data carriers; use this JEP when inheritance and super(...) are in play.

Exactly one next constructor

You still invoke either super(...) or this(...) once (explicitly or via the implicit super()). The prologue does not replace chaining — it sits in front of it.

Epilogue return

Bare return; is allowed in the epilogue. return is a compile-time error in the prologue. You still cannot return a value from a constructor.

Reading this too early

Even after assigning a field in the prologue, you must not treat the object as constructed: no instance method calls, no passing this to other code that expects a finished instance.

Cheat sheet

Ctor(...) {
  // prologue: validate, compute, assign own fields (no initializers)
  super(...);   // or this(...)
  // epilogue: normal instance code
}

Java 25+ (JEP 513); no preview flag
Prologues run bottom-up; epilogues top-down
Good: fail-fast before super; prep args; early subclass field init
Avoid: mega-constructors; relying on overridable calls from super
Watch: fields with initializers; no instance calls in prologue

Do:

  • Put fail-fast checks in the prologue so bad args never reach super.
  • Assign subclass fields in the prologue when superclass code might observe them early.
  • Keep heavy construction logic in factories when a constructor would become a script.

Don’t:

  • Call instance methods or pass this out from the prologue.
  • Expect to assign fields that already have = ... initializers before super.
  • Treat flexible bodies as permission for superclass constructors to call overridable methods.

Pros and cons

Pros

  • Readable fail-fast — no static-helper smuggling into super(...)
  • Clear prologue / epilogue split for what runs before vs after the next constructor
  • Stronger subclass integrity when fields must be set before superclass code runs
  • Final in Java 25 — no preview tax

Cons

  • Early construction rules are easy to trip over (no instance calls, initializer restrictions)
  • Does not fix bad superclass design that leaks this or calls overrides
  • Requires Java 25+ for the standard language feature
  • Temptation to stuff too much into constructors instead of factories

Wrap-up

Flexible constructor bodies (JEP 513) drop the “first statement must be super / this” rule. Use a prologue to validate, prepare arguments, and initialize this class’s fields; use the epilogue for ordinary post-super setup.

Start by deleting the verifyX static helpers that existed only to sneak checks into super(...). Keep constructors short. When Java’s ceremony still feels heavy for scripts and demos, the next Java 25 story is compact source files and instance main — void main() without the boilerplate class shell.

Optional next Drop the class shell and write void main() for scripts and demos. Compact Source Files and Instance Main