JEP 513 Java 25: Flexible Constructor Bodies Explained
-
Last Updated: January 15, 2026
-
By: javahandson
-
Series
Learn Java in a easy way
JEP 513 Java 25 introduces flexible constructor bodies, allowing safe statements before #super() or #this(). Learn prologue vs epilogue, safety guarantees, records, enums, and before–after constructor examples in Java 25.
In Java, constructors are special methods used to create and initialise objects. Whenever we create an object using new, Java follows a strict construction flow to make sure the object is created safely and predictably.
One important part of this flow is constructor chaining. If a class has a parent class, Java ensures that the parent constructor runs before the child constructor logic. This guarantees that the object is built step by step, starting from the top of the inheritance hierarchy.
For many years, Java enforced a strict rule: A constructor must start with either #super(…) or #this(…).
This meant:
Example of what was not allowed earlier:
package com.javahandson.jep513;
class Parent {
Parent(int x) {
System.out.println("Hello : " + x);
}
}
class Child extends Parent {
Child(int x) {
if (x < 0) { // Not allowed before Java25
throw new IllegalArgumentException();
}
super(x);
}
}
public class Test {
public static void main(String[] args) {
Child child = new Child(10);
}
}
Output: java: call to super must be first statement in constructor
This rule often made constructors:
JEP 513: Flexible Constructor Bodies improves this situation. It allows certain statements to appear before #super() or #this() calls, making constructors more expressive and readable. Importantly, this is a refinement of existing rules, not a breaking change.
JEP 513 does not change what constructors do — it improves how naturally we can write them.
Before understanding JEP 513, it is important to know how Java creates an object and executes constructors. The old constructor rules were closely tied to this process and were mainly about safety, not convenience.
When we create an object using new, Java follows a well-defined sequence.
First, memory is allocated for the entire object. This memory includes fields from both the parent class and the child class. At this stage, no constructor has executed, and the object is not yet usable.
Next, Java performs default initialisation. All instance fields receive their default values, such as 0 for numbers, false for booleans, and null for object references. This happens automatically and before any constructor logic runs.
After default initialization, Java executes the parent class constructor. If the constructor does not explicitly call super(…), Java inserts a default super() call. This step initialises the parent portion of the object and is mandatory in every object creation.
Only after the parent constructor completes does Java execute the child constructor. This is where child-specific initialization and logic occur. At the end of this step, the object is fully constructed and safe to use.
package com.javahandson.jep513;
class Parent {
Parent(int x) {
System.out.println("Parent Constructor : " + x);
}
}
class Child extends Parent {
Child(int x, int y) {
super(x);
System.out.println("Child Constructor : " + y);
}
}
public class Test {
public static void main(String[] args) {
new Child(10, 20);
}
}
Output:
Parent Constructor : 10
Child Constructor : 20
When a constructor runs, Java does not treat the entire constructor body equally. Conceptually, constructor execution happens in two phases: the prologue and the epilogue. These phases explain why constructor rules existed long before JEP 513.
The constructor prologue is the phase that executes before constructor chaining. Constructor chaining means calling either #super(…) to invoke the parent constructor or #this(…) to invoke another constructor in the same class.
At the prologue stage:
This means the object exists, but it is not fully initialised.
Before JEP 513, Java allowed almost no user-written code in the prologue. As a result, super() or this() had to appear as the very first statement.
Consider this example:
package com.javahandson.jep513;
class Parent {
Parent(int x) {
System.out.println("Parent Constructor : " + x);
}
}
class Child extends Parent {
int x;
Child(int value) {
System.out.println("Child Constructor : " + value); // not allowed earlier
super(value);
}
}
public class Test {
public static void main(String[] args) {
new Child(10);
}
}
Output: java: call to super must be first statement in constructor
Here, even though the print statement looks harmless, Java rejected it because the object was still in its prologue phase. Accessing instance state or performing logic at this stage could lead to unsafe behaviour.
The constructor epilogue begins after constructor chaining completes. Once #super(…) or #this(…) finishes executing, the object is fully constructed.
At this point:
package com.javahandson.jep513;
class Parent {
Parent(int x) {
System.out.println("Parent Constructor : " + x);
}
}
class Child extends Parent {
int x;
Child(int value) {
super(value); // constructor chaining
x = value * 2; // epilogue starts here
print(); // safe
}
void print() {
System.out.println("Child value : "+x);
}
}
public class Test {
public static void main(String[] args) {
new Child(10);
}
}
Output:
Parent Constructor : 10
Child value : 20
The epilogue is where normal constructor logic belongs. Java places no special restrictions here because the object is now in a valid and stable state.
Java’s strict constructor ordering was designed to protect object safety, not to restrict developers.
Before the parent constructor runs, the object is only partially constructed. Allowing code to execute freely at this stage could expose an invalid state or lead to subtle bugs that are hard to detect.
One common risk is calling overridable methods too early:
package com.javahandson.jep513;
class Parent {
Parent() {
init();
}
void init() { }
}
class Child extends Parent {
int x = 10;
Child() {
super();
}
@Override
void init() {
System.out.println("Value of x is : "+x); // x not initialized yet
}
}
public class Test {
public static void main(String[] args) {
new Child();
}
}
Output: Value of x is : 0
In this example, the parent constructor calls a method that is overridden in the child class. When that method executes, the child’s fields have not been initialized yet, leading to unexpected behavior.
Strict ordering prevented problems such as:
Leaving objects in an inconsistent state
By forcing #super() or #this() to be the first statement, Java guaranteed that the parent part of the object is always initialised before child logic begins.
This design ensured one critical promise: An object should never be observed in a partially constructed state.
JEP 513 builds on this foundation by introducing flexibility in the prologue, while still preserving this core safety guarantee.
For many years, Java enforced a strict rule in constructors: the first statement must be either #super(…) or #this(…). Although this rule often felt limiting, it was introduced for very specific safety reasons and was never arbitrary.
The most important guarantee was that the parent part of the object must be fully initialized before any child-specific logic runs. Every child object contains a parent object inside it. If child code were allowed to run before the parent constructor, the child could access parent fields or behavior that had not yet been set up, leading to unpredictable results.
Another critical reason for this rule was to prevent the ‘this’ reference from escaping too early. Before the parent constructor completes, the object exists only in a partially constructed state. Exposing this at that moment could allow other code to observe or interact with an invalid object.
Because of this, Java rejected even simple-looking code at compile time:
class Child extends Parent {
Child(int x) {
System.out.println(x); // compile-time error
super(x);
}
}
The compiler enforces this with an error stating that the constructor call must be the first statement. This strict behavior ensured that no logic—logging, validation, or method calls—could run before the parent constructor finished.
By enforcing this rule, Java guaranteed that:
While this approach sometimes made constructors harder to write cleanly, it kept object construction safe and predictable. JEP 513 builds on this foundation by improving flexibility without removing these core safety guarantees.
JEP 513 introduces a focused and carefully designed change to how constructor bodies are written in Java. It does not rewrite constructor semantics or relax safety rules arbitrarily. Instead, it refines where certain code is allowed to appear.
The core change is simple but powerful: Java now allows certain statements to appear before #super() or #this() inside a constructor.
These statements are part of what is now explicitly recognised as the constructor prologue.
With JEP 513, the constructor body is clearly divided into two phases:
Prologue: statements that execute before constructor chaining
Epilogue: statements that execute after constructor chaining
This means code like validation or argument preparation can now appear naturally at the top of the constructor, before calling #super(…) or #this(…).
class Child extends Parent {
Child(int value) {
if (value < 0) { // now allowed
throw new IllegalArgumentException();
}
super(value); // constructor chaining
System.out.println("Ready"); // epilogue
}
}
The code before #super(value) belongs to the prologue, while the code after it belongs to the epilogue.
Although JEP 513 allows statements before #super() or #this(), it does not relax Java’s safety model.
These rules still apply:
In other words, Java now allows more natural constructor code, but only when it is safe to do so. JEP 513 improves readability and expressiveness while preserving the same guarantees that Java constructors have always provided.
With JEP 513, Java encourages developers to think about constructors in a more structured way. Instead of treating the constructor body as one continuous block, it is now helpful to see it as two distinct phases: the prologue and the epilogue. This mental model explains both the new flexibility and the continued restrictions.
The prologue is the part of the constructor that executes before constructor chaining happens. Constructor chaining means calling super(…) or this(…).
At this point in time:
Even though the object exists in memory, it is still incomplete. Because of this, the prologue remains a highly restricted phase. JEP 513 does not turn the prologue into a normal code block; it only allows carefully controlled statements that do not depend on instance state.
The prologue is best used for:
It is not meant for accessing fields, calling instance methods, or performing business logic.
The epilogue begins immediately after constructor chaining completes.
Once #super(…) or #this(…) finishes:
From this point onward, Java imposes no special constructor-specific restrictions. The epilogue behaves like any normal instance method body. This is where child-specific initialisation, logging, method calls, and side effects naturally belong.
In practical terms, if a piece of logic needs access to ‘this’ or instance fields, it belongs in the epilogue.
Java draws a clear boundary between the prologue and the epilogue to preserve a critical safety guarantee: an object should never be observed in a partially constructed state.
Before the parent constructor runs, exposing instance state could lead to incorrect behavior or subtle bugs that are extremely difficult to debug. After construction completes, those risks disappear.
JEP 513 builds on this distinction rather than removing it. It allows more expressive code in the prologue, where it is safe, while continuing to enforce strict rules where object safety could be compromised. This balance is what makes the new constructor model both powerful and safe.
JEP 513 makes the constructor prologue visible and usable, but it does not turn it into a free-for-all. The prologue is still a sensitive phase of object construction, so Java allows only those operations that are guaranteed to be safe.
To use the prologue correctly, it helps to clearly understand what is allowed, what is not, and why.
The prologue exists before the parent constructor runs, so Java only allows operations that do not depend on the object’s state.
1. Local variable declarations are allowed because they live on the stack and have no connection to the object being constructed.
package com.javahandson.jep513;
class Parent {
Parent(int x) {
System.out.println("Parent absolute value: " + x);
}
}
class Child extends Parent {
Child(int value) {
int normalized = Math.abs(value); // allowed
super(normalized);
}
}
public class Test {
public static void main(String[] args) {
new Child(-100);
}
}
Output: Parent absolute value: 100
2. Parameter validation is also allowed, as it works only with constructor parameters and does not touch instance state.
package com.javahandson.jep513;
class Parent {
Parent(int x) {
System.out.println("Parent absolute value: " + x);
}
}
class Child extends Parent {
Child(int value) {
if (value < 0) {
throw new IllegalArgumentException("Value must be positive");
}
super(value);
}
}
public class Test {
public static void main(String[] args) {
new Child(-100);
}
}
Output: Exception in thread "main" java.lang.IllegalArgumentException: Value must be positive
3. Another common and important use case is computing arguments for #super(…) or #this(…). This was one of the main motivations behind JEP 513.
package com.javahandson.jep513;
class Parent {
Parent(int x) {
System.out.println("Parent adjusted value: " + x);
}
}
class Child extends Parent {
Child(int value) {
int adjusted = value * 2;
super(adjusted);
}
}
public class Test {
public static void main(String[] args) {
new Child(-100);
}
}
Output: Parent adjusted value: -200
All of these operations are safe because they do not observe or modify the object being constructed.
Anything that depends on the object’s identity or state is still disallowed.
1. Accessing instance fields is not allowed because fields still contain default values and may depend on parent initialisation.
package com.javahandson.jep513;
class Parent {
Parent(int x) {
System.out.println("Parent value: " + x);
}
}
class Child extends Parent {
int x;
Child(int value) {
System.out.println(x); // not allowed
super(value);
}
}
public class Test {
public static void main(String[] args) {
new Child(100);
}
}
Output: java: cannot reference x before supertype constructor has been called
2. Calling instance methods is also forbidden, because such methods may access fields, rely on overridden behaviour, or expose this.
package com.javahandson.jep513;
class Child extends Parent {
int x;
Child(int value) {
printX(); // not allowed in prologue
super(value);
}
void printX() {
System.out.println(x);
}
}
At the point where #printX() is called:
Even though the method call looks harmless, #printX() reads an instance field that does not yet represent a valid or intended state. Java disallows this to prevent code from observing incorrect object state.
3. Using ‘this’ directly is not allowed for the same reason. At this stage, ‘this’ represents a partially constructed object, and exposing it would break Java’s safety guarantees.
class Child extends Parent {
Child() {
log(this); // not allowed
super();
}
void log(Child c) {
System.out.println(c);
}
}
Passing this to another method would expose a half-built object. Java blocks this to prevent the object from escaping before construction completes.
4. Finally, returning from a constructor in the prologue is disallowed. Constructors must complete their chaining and epilogue to ensure the object is fully initialised.
class Child extends Parent {
Child(int value) {
if (value < 0) {
return; // not allowed
}
super(value);
}
}
Output: java: 'return' not allowed before explicit constructor invocation
Even though constructors do not return values, an early return would skip constructor chaining and leave the object in an invalid state. Java therefore rejects this at compile time.
All prologue restrictions exist for one simple reason: the object is not fully constructed yet.
Allowing access to instance state, methods, or this itself could:
JEP 513 relaxes syntax, not safety. It allows more natural constructor code, but only where Java can still guarantee that objects are created in a valid and predictable state.
This is why the prologue is powerful—but intentionally limited.
JEP 513 applies to all constructors, but records and enums already had extra constructor rules even before this JEP. So this section matters because many people assume “flexible constructor bodies” means the same freedom everywhere — it doesn’t.
The good news is that records and enums do benefit from JEP 513, mainly because they can now put safe statements in the prologue before their required constructor delegation call.
Records have stricter constructor rules than normal classes, and JEP 513 does not remove them.
Canonical record constructors – A canonical constructor is the one whose parameter list matches the record components exactly (same “shape” as the record header). Canonical record constructors must not contain any explicit constructor invocation — meaning we cannot write #this(…) or #super(…) inside it. That restriction remains unchanged.
Example (compact canonical constructor — no this(…)/super(…) allowed):
record User(String name, int age) {
User {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("name required");
}
if (age < 0) {
throw new IllegalArgumentException("age must be >= 0");
}
// No explicit this(...) or super(...) here (still not allowed)
}
}
Notice something important: this constructor already “feels” like it has a prologue, but in record canonical constructors, there is no explicit constructor invocation to place statements before — so the big benefit of JEP 513 isn’t here. The canonical constructor was already the natural place for validation.
Non-canonical record constructors – A non-canonical record constructor is any constructor whose parameter list does not match the record components. For these, Java requires an alternate constructor invocation: we must delegate to another constructor using #this(…), and we cannot use #super(…). These rules remain unchanged.
This is where JEP 513 helps most: non-canonical record constructors can now have statements before this(…).
Before JEP 513, this was illegal:
record User(String name, int age) {
User(String name) {
if (name == null) { // not allowed earlier
throw new IllegalArgumentException();
}
this(name.trim(), 18);
}
}
With JEP 513, the intent becomes valid and readable:
record User(String name, int age) {
User(String name) {
if (name == null || name.isBlank()) { // allowed in prologue now
throw new IllegalArgumentException("name required");
}
this(name.trim(), 18); // must still be this(...)
}
}
What to remember for records:
1. Canonical constructors: still no explicit #this(…) or #super(…).
2. Non-canonical constructors: must call #this(…), not #super(…) — but can now have a prologue before #this(…).
Enum constructors are also special. Even though every enum implicitly extends java.lang.Enum, Java, does not let an Enum call a superclass constructor explicitly. So enum constructors:
That rule remains unchanged.
So, where does JEP 513 help? In enums, the benefit is similar to non-canonical records: we can now place statements before #this(…).
enum Status {
OK(200),
NOT_FOUND(404);
private final int code;
Status(int code) {
this.code = code;
}
Status(String codeText) {
int parsed = Integer.parseInt(codeText); // allowed before this(...)
this(parsed); // still must be this(...)
}
}
This pattern used to be awkward because we had to move parsing/validation into a static helper just to keep this(…) first. Now the enum constructor can do it directly.
What to remember for enums:
Even with JEP 513, records and enums still have special constructor rules. Many compiler errors happen because developers assume the new flexibility removes those rules — it doesn’t.
Below are the most common mistakes.
1. Calling #super(…) in a Record Constructor – Records implicitly extend java.lang.Record, but Java does not allow explicit calls to super(…) in record constructors.
record User(String name) {
User {
super(); // still not allowed
}
}
Even after JEP 513, this remains illegal. Record constructors never allow explicit superclass constructor calls.
2. Using #super(…) instead of #this(…) in Non-Canonical Record Constructors – Non-canonical record constructors must delegate to another constructor using #this(…), not #super(…).
record User(String name, int age) {
User(String name) {
super(); // illegal
this(name, 18); // must be this(...)
}
}
JEP 513 allows a prologue before #this(…), but the delegation rule itself has not changed.
3. Accessing Record components or fields in the Prologue – Even though record components look like parameters, they are still instance state. Accessing them in the prologue is not allowed.
record User(String name, int age) {
User(String name) {
System.out.println(this.name()); // not allowed in prologue
this(name, 18);
}
}
Until constructor chaining completes, the record components are not fully initialised. The same prologue restrictions apply here as with normal classes.
JEP 513 makes constructor bodies more flexible, but it does not relax the special rules of records and enums. If something was fundamentally unsafe before, it is still unsafe now — just easier to write safe code where it is allowed.
At first glance, JEP 513 may raise a natural question: if Java is allowing more freedom in constructors, why does it still feel so strict?
The answer lies in Java’s long-standing design philosophy: flexibility is welcome, but never at the cost of object safety.
Constructors deal with one of the most delicate phases of a program’s lifecycle — object creation. During this phase, an object may exist in memory but not yet be valid.
If Java were to fully relax constructor rules and allow unrestricted code before #super(…), developers could:
These problems are notoriously hard to debug and can lead to subtle runtime bugs that surface far away from the constructor itself. Java deliberately prevents such situations at compile time, even if that sometimes feels restrictive.
JEP 513 is careful about what it changes.
It allows code in the constructor prologue only when Java can guarantee that the code does not depend on object state. Anything that could observe, modify, or expose the partially constructed object is still disallowed.
In practice, this means:
By keeping these guardrails intact, Java ensures that objects are never observed in an invalid or half-constructed state — even with the added flexibility.
JEP 513 improves how constructors are written, not when objects become safe to use.
JEP 513 makes constructors easier to write and read, but it is not meant to turn constructors into general-purpose logic blocks. Knowing when to use the new flexibility — and when to avoid it — is important for writing clean and maintainable code.
One of the best uses of the constructor prologue is parameter validation. Validating inputs early makes constructors safer and more expressive, and JEP 513 allows this to happen naturally at the top of the constructor.
Another strong use case is pre-processing constructor arguments. If a value needs to be normalised, transformed, or adjusted before being passed to #super(…) or #this(…), the prologue is the right place to do it.
JEP 513 also improves constructor chaining readability. Instead of pushing logic into helper methods or complex expressions inside #super(…), we can now prepare values step by step and clearly delegate to another constructor.
In all these cases, the logic remains simple, local, and independent of object state.
The prologue should not be used for business logic. Constructors exist to create objects, not to perform domain operations, trigger workflows, or interact with external systems.
Similarly, complex computation does not belong in the prologue. Heavy logic makes constructors harder to reason about and often signals that the responsibility belongs elsewhere, such as a factory or a builder.
If a piece of code needs access to instance fields, calls instance methods, or relies on fully initialised state, it belongs in the epilogue — or outside the constructor entirely.
JEP 513 is introduced as a preview feature in Java 25.
This means:
Preview status allows developers to adopt the feature early while giving the Java platform a chance to refine it before finalisation. Used correctly, JEP 513 makes constructors cleaner without compromising safety — but it works best when applied with restraint.
JEP 513 is a thoughtful refinement to Java’s constructor model. It does not introduce new concepts or change how object construction works internally. Instead, it removes an old syntactic restriction that often forced developers into awkward workarounds.
By making the constructor prologue explicit and usable, Java allows validation and argument preparation to live where they naturally belong—at the top of the constructor. At the same time, the language continues to strictly protect object safety by disallowing access to instance state before construction completes.
This balance is what makes JEP 513 important. It improves readability and developer experience without compromising Java’s core guarantees. Even after this change, Java remains intentionally strict where it matters most: preventing partially constructed objects from being observed.
As with any preview feature, JEP 513 should be adopted thoughtfully. But its direction is clear—it simplifies real-world code while staying true to Java’s long-standing philosophy of safety, clarity, and predictability.