Definition
- If a constructor throws an exception, the
newexpression never returns a reference. The variable staysnull(or the assignment never happens). - The partially-constructed object is unreachable and will be garbage collected. The caller cannot access the half-built object.
- However, if the constructor opened resources (file handles, DB connections, threads) before the exception, those resources leak. They are allocated but nobody holds a reference to close them.
- Fix: use try-catch inside the constructor to close resources on failure, or use a static factory method that manages resource lifecycle outside the constructor.
Building a new branch for National Bank of India: you install the vault (resource 1), then the alarm system (resource 2), then the cameras (resource 3). If camera installation fails, the branch is never opened to customers (object never returned). But the vault and alarm are already installed with nobody holding a key to disable them (resource leak).
Understanding the Concepts
What happens when a constructor throws?
The new expression never returns. The variable stays null, and the partially-constructed object is unreachable.
package com.bank.demo;
public class ConstructorExceptionDemo {
static class TradeProcessor {
TradeProcessor(String config) {
System.out.println("Step 1: config loaded");
if (config.equals("BAD")) {
throw new IllegalArgumentException("Invalid config: " + config);
}
System.out.println("Step 2: processor ready");
}
}
public static void main(String[] args) {
TradeProcessor processor = null;
try {
processor = new TradeProcessor("BAD");
} catch (IllegalArgumentException e) {
System.out.println("Caught: " + e.getMessage());
}
System.out.println("processor is: " + processor);
// processor is null. The new expression never returned.
}
}
Step 1: config loaded
Caught: Invalid config: BAD
processor is: null
How do resource leaks happen in constructors?
If the constructor opens resources and then throws, those resources are allocated but nobody has a reference to close them.
package com.bank.demo;
public class ConstructorLeakDemo {
static class LeakyProcessor {
private final String connection;
private final String fileHandle;
LeakyProcessor() {
this.connection = "DB-Connection-Open";
System.out.println("Opened: " + connection);
this.fileHandle = "File-Handle-Open";
System.out.println("Opened: " + fileHandle);
// This line throws AFTER both resources are opened
throw new RuntimeException("Schema validation failed");
// connection and fileHandle are LEAKED.
// Nobody has a reference to close them.
}
}
public static void main(String[] args) {
try {
new LeakyProcessor();
} catch (RuntimeException e) {
System.out.println("Caught: " + e.getMessage());
System.out.println("Resources are leaked. No reference to close them.");
}
}
}
Opened: DB-Connection-Open
Opened: File-Handle-Open
Caught: Schema validation failed
Resources are leaked. No reference to close them.
How do you fix resource leaks in constructors?
Use try-catch with temporary variables to clean up on failure.
package com.bank.demo;
public class SafeConstructorDemo {
static class SafeProcessor {
private final String connection;
private final String fileHandle;
SafeProcessor() {
String tempConn = null;
String tempFile = null;
try {
tempConn = "DB-Connection";
System.out.println("Opened: " + tempConn);
tempFile = "File-Handle";
System.out.println("Opened: " + tempFile);
// Simulate failure
throw new RuntimeException("Validation failed");
} catch (RuntimeException e) {
// Clean up everything opened so far
if (tempFile != null) System.out.println("Closed: " + tempFile);
if (tempConn != null) System.out.println("Closed: " + tempConn);
throw e; // Rethrow after cleanup
}
// This line only reached on success:
// this.connection = tempConn;
// this.fileHandle = tempFile;
}
}
public static void main(String[] args) {
try {
new SafeProcessor();
} catch (RuntimeException e) {
System.out.println("Caught: " + e.getMessage());
System.out.println("Resources cleaned up before rethrowing.");
}
}
}
Opened: DB-Connection
Opened: File-Handle
Closed: File-Handle
Closed: DB-Connection
Caught: Validation failed
Resources cleaned up before rethrowing.
What is the static factory method pattern?
A static factory manages the resource lifecycle outside the constructor, ensuring cleanup on failure.
package com.bank.demo;
public class FactoryPatternDemo {
static class TradeProcessor implements AutoCloseable {
private final String connection;
private TradeProcessor(String connection) {
this.connection = connection;
}
static TradeProcessor create(String config) {
String conn = "DB-Conn-" + config;
System.out.println("Opened: " + conn);
try {
validate(config);
return new TradeProcessor(conn);
} catch (RuntimeException e) {
System.out.println("Closed: " + conn); // Cleanup on failure
throw e;
}
}
private static void validate(String config) {
if (config.equals("BAD")) throw new RuntimeException("Invalid config");
}
@Override public void close() {
System.out.println("Closed: " + connection);
}
public static void main(String[] args) {
try {
TradeProcessor p = TradeProcessor.create("BAD");
} catch (RuntimeException e) {
System.out.println("Caught: " + e.getMessage());
}
}
}
}
Opened: DB-Conn-BAD
Closed: DB-Conn-BAD
Caught: Invalid config
What should a senior engineer know?
- Finalizers and Cleaners. A partially-constructed object whose constructor threw will NOT have its finalizer called (pre-Java 9) and should not rely on Cleaner (Java 9+) for resource cleanup.
- Builder pattern. The Builder validates everything in build() before constructing the object, preventing partial construction entirely.
- Spring beans. If a Spring @Service constructor throws, the ApplicationContext fails to start. Spring handles cleanup of already-constructed beans.
What are common interview follow-up questions?
- Can the caller access a partially-constructed object? (No, the new expression never returns.)
- What happens to the partially-constructed object? (It is unreachable and GC'd.)
- How do you prevent resource leaks in constructors? (try-catch with cleanup, or static factory.)
- Is the object's finalizer called if the constructor throws? (No.)
Visual Overview
new TradeProcessor(config)
│
├── Step 1: open connection (resource allocated)
├── Step 2: open file handle (resource allocated)
├── Step 3: validate (throws!)
│
▼
Constructor throws
│
├── new expression NEVER returns
├── variable stays null
├── Object unreachable (GC'd)
└── connection + file handle: LEAKED
Fix: try-catch in constructor
│
├── catch: close file handle
├── catch: close connection
└── rethrow after cleanup
Key Takeaway
When a constructor throws an exception, the new expression never returns. The variable stays null and the partially-constructed object is unreachable, so the caller cannot use an inconsistent object. However, resources opened before the throw (database connections, file handles, threads) are leaked because nobody holds a reference to close them.
At National Bank of India, a BatchSettlementProcessor constructor opens a DB connection, opens a file, then validates the schema. If validation throws, the connection and file handle are leaked. After 500 failed attempts, the connection pool is exhausted and the file descriptor limit is hit, hanging the entire system.
The fix is to use temporary variables with try-catch inside the constructor, closing all resources in the catch block before rethrowing. The static factory method pattern is even cleaner: the factory manages the resource lifecycle and only calls the private constructor when everything is validated.
Remember one sentence: a throwing constructor never returns an object reference, but resources opened before the throw are leaked unless you explicitly clean them up.
---