skip to content

Can a constructor throw a checked exception in Java, and what are the implications?

level: seniorimportance: should knowfreq 45%

answer

  1. Yes — constructors can declare throws
  2. On throw, new returns NO reference (no half-built object handed back)
  3. Subclass must declare checked exceptions thrown by super(...)
  4. Beware leaked this + leaked resources during partial construction
  5. Prefer unchecked (IllegalArgumentException) for plain validation

basics

~20 s

Yes. A constructor can declare throws and throw checked exceptions just like a method. If it throws, the object is not created, so the caller must handle or declare the exception, and there is no half-built object returned.

solid answer

~60 s

Constructors may throw checked exceptions by listing them in a `throws` clause; callers must then handle or propagate them. If a constructor throws (anywhere in its body, or because a superclass `super(...)` call throws), construction fails and `new` does not return a reference — there is no partially-initialized object handed back. This is useful for validating arguments or acquiring resources (e.g. opening a `FileInputStream` throws `FileNotFoundException`). Two important subtleties: (1) a subclass constructor must declare the checked exceptions thrown by the `super(...)` constructor it calls, since those propagate through; (2) even though no reference is returned, if the constructor already published `this` somewhere (registered it, started a thread, added to a collection) or allocated resources, those can leak — and the object may still be reachable for finalization. So you should validate early, avoid leaking `this`, and clean up any partially-acquired resources (try/catch or try-with-resources) before the exception escapes. Many teams prefer throwing **unchecked** exceptions (e.g. `IllegalArgumentException`) for plain argument validation and reserve checked exceptions for genuinely recoverable failure modes.

code

java · 13 lines
java
public class Resource {
    private final InputStream stream;

    public Resource(Path path) throws IOException {  // checked exception declared
        // validate first (unchecked) — leaves nothing to clean up on failure
        Objects.requireNonNull(path, "path");
        // acquire resource; if load() below threw, we'd close in a catch
        this.stream = Files.newInputStream(path);
    }
}

// caller MUST handle or declare:
// try { var r = new Resource(p); } catch (IOException e) { /* no object created */ }

go deeper

for a junior

Knows a constructor can throw and that, on failure, you don't get an object back.

for a middle

Adds the throws-clause mechanics and that the caller must handle/declare it, and can give an example like FileInputStream throwing FileNotFoundException.

for a senior

Covers super() exception propagation, partial-construction resource leaks and leaked this, and the checked-vs-unchecked design choice.

for a principal

Sets policy on exception design in constructors vs static factories, mitigates finalizer/leak attacks and invariant exposure, and balances fail-fast construction against builder/Optional-returning alternatives across an API surface.

## Background: checked vs unchecked exceptions In Java an **exception** is an object signaling that something went wrong. There are two families: - **Checked exceptions** (subclasses of `Exception` but not `RuntimeException`, e.g. `IOException`, `SQLException`): the compiler *forces* you to deal with them — either catch them or declare them with `throws`. They model recoverable, expected failure conditions. - **Unchecked exceptions** (`RuntimeException` and its subclasses, e.g. `IllegalArgumentException`, `NullPointerException`): the compiler does *not* force handling. They typically model programming errors. ## Can a constructor throw a checked exception? **Yes.** A constructor is like a method for exception purposes: it can have a `throws` clause and can throw checked exceptions: ```java public class Config { private final Properties props; public Config(Path file) throws IOException { // declares a checked exception try (var in = Files.newInputStream(file)) { this.props = new Properties(); this.props.load(in); // may throw IOException } } } ``` The caller of `new Config(path)` must now catch `IOException` or declare it — exactly as if calling a method that throws it. ## What happens to the object when the constructor throws? When a constructor throws, the `new` expression completes **abruptly**: it does **not** produce a reference. The variable you were assigning to is never assigned. So the caller never receives a half-built object — there is no `Config` instance returned. ```java Config c; try { c = new Config(path); // if this throws, c is never assigned } catch (IOException e) { // handle; c does not refer to a Config } ``` ## Where can the throw come from? Three places: 1. The constructor body's own code. 2. A field initializer or instance initializer block (these run as part of construction). 3. A `super(...)` call — if the superclass constructor throws a checked exception, it propagates out of the subclass constructor too. Therefore a subclass constructor **must declare** any checked exception its `super(...)` can throw: ```java class Base { Base() throws IOException { /* ... */ } } class Derived extends Base { Derived() throws IOException { // MUST declare it; super() can throw it super(); } } ``` ## The danger: partial construction and resource leaks Even though no reference is *returned*, the object's memory was allocated and parts of it may have run before the throw. Two hazards: - **Leaked `this`:** if the constructor published the object before throwing — e.g. `registry.add(this)`, `new Thread(this).start()`, or registered itself as a listener — then a *partially-initialized* object is now reachable elsewhere even though the constructor failed. This is dangerous: other code may observe an object with broken invariants. **Rule: don't let `this` escape during construction**, especially before validation completes. - **Acquired resources:** if the constructor opened a file/socket/connection and then a later line throws, that resource leaks unless you close it. Use try/catch or try-with-resources inside the constructor to release anything already acquired before letting the exception propagate. There is also a historical finalizer-attack concern: a malicious subclass could override `finalize()` and, if a superclass constructor throws after partly initializing, get a reference to the broken object. The classic defense is to validate parameters *before* any state is set (or use a private constructor + static factory, or make the class final). Finalizers are deprecated, but the principle — validate before exposing state — still holds. ## Best practices - **Validate arguments first**, before acquiring resources or assigning state, so a failure leaves nothing to clean up. - For simple argument checks (null, range), prefer **unchecked** exceptions like `IllegalArgumentException`/`NullPointerException` (or `Objects.requireNonNull`) — these are programming errors, not recoverable conditions, so forcing the caller to declare `throws` adds noise. - Reserve **checked** exceptions for genuinely recoverable failures (I/O, parsing, external resources). - If a constructor needs to do significant fallible work, consider a **static factory method** that does the work and throws, which reads more naturally and can return alternatives. - Always **release partially acquired resources** before the exception escapes; never let `this` leak mid-construction.

  • If a constructor throws, can a partially-constructed object ever still be observed?
    The new expression returns no reference, but if the constructor leaked this (added itself to a collection, started a thread, registered a listener) before throwing, that broken object is reachable elsewhere. Historically a malicious finalize() override could also grab it. Defense: validate before setting state and never let this escape during construction.
  • When should a constructor throw checked vs unchecked exceptions?
    Use checked exceptions for genuinely recoverable failures the caller is expected to handle (I/O, parsing). Use unchecked (IllegalArgumentException, NullPointerException via Objects.requireNonNull) for argument validation / programming errors, so callers aren't forced into throws clauses for bugs.

saying these in an interview costs you the question

  • Claiming constructors cannot throw checked exceptions
  • Thinking a half-initialized object is returned when a constructor throws
  • Forgetting the subclass must declare checked exceptions thrown by super()
  • Ignoring resource leaks / leaked this when a constructor fails partway
  • Using checked exceptions for trivial null/range validation

context