Concepts / Constructors and Instance Variables

Constructors and Instance Variables

A custom exception class extends Exception or RuntimeException.

  • Programming
Interactive lab

Try it: try / except / else / finally

How an exception jumps out of a try block to the first matching except clause, when else runs, and why finally always runs.

How it works

  1. Statements in try run until one raises an exception; the rest of try is skipped.
  2. Python checks the except clauses in order and runs the first one whose type matches.
  3. If nothing was raised, the else block runs instead.
  4. finally runs in every case.

Default run (9 steps): Call safe_divide('4'). … Return 25.0. Output was: Worked: 25.0 / Done.

Simplified: One fixed function; int() and / are modelled exactly (including how Python prints floats), but nothing is executed as Python.

Educational simulation

Loading the simulation…

A Ship That Was Destroyed at a Position

Java programs use exceptions to signal that something has gone wrong. The built-in exception types describe general problems. Often, though, a program needs to report a problem in its own terms: a string that could not be parsed, or a ship that was destroyed at a particular screen position. In that case the program can define its own exception class. This article works through custom exception classes that build exactly these kinds of error objects, and it focuses on the two ideas that make them work: the constructor, and the instance variables that hold extra information.

What do you think happens?

Before reading on: which existing class does a custom ShipDestroyed exception extend?

  • Exception

  • RuntimeException

  • ParseError

Reveal answer
Answer:

RuntimeException

The source shows two choices. ParseError extends Exception, while ShipDestroyed extends RuntimeException. Each custom class sits directly beneath the class it extends.

Try making three predictions on paper before reading the rest of the article: which existing class each new class extends, what the constructor receives as parameters, and what information the object still holds after the constructor finishes. Writing guesses first makes it easier to notice where your reasoning was right and where it was not.

Choosing a Superclass for the Custom Exception

Definition

A custom exception class extends Exception or RuntimeException. The class name describes the error, and the superclass determines the category the new class belongs to.

The source shows both choices. ParseError extends Exception, while ShipDestroyed extends RuntimeException. The tree below shows how these two classes relate to the superclasses they extend. The superclass sits above, and each custom class sits directly beneath the one it extends. Notice that the source material presents these as two options in the same family of exception classes, so the choice between them is a decision the author makes when defining the error.

ExceptionParseErrorRuntimeExceptionShipDestroyedextendsextends
Which superclass does each custom exception class sit beneath in the source material?

The Minimum Shape of a Custom Exception

The simplest custom exception class in the source extends Exception and contains only a constructor. The class declares no fields and no other methods. Everything it does is defined by its name, its superclass, and its constructor. The constructor accepts a message, and its body is a single call to super(message), which hands the message to the superclass constructor.

java
Notes on the code
  • The class name ParseError describes the error.
  • extends Exception names the superclass.
  • The constructor parameter message carries the text of the error.
  • super(message) forwards that text to the superclass constructor.

This class is the minimum shape the rest of the article builds on. The example code above is an illustrative reconstruction of the pattern the source describes, not a listing copied from the source. What matters is the pattern itself: a name, a superclass, and a constructor that forwards the message upward.

Tracing the Constructor Call

The constructor does not store the message in a field of the custom class. It forwards the message to the superclass constructor, which is responsible for setting up the error message. When a ShipDestroyed object is created, the calls happen in a fixed order, shown in the sequence diagram below. Read the arrows from top to bottom.

CallerShipDestroyedconstructorRuntimeExceptionconstructor1. new ShipDestroyed with four values2. super(message)3. superclass finishes setup4. remaining fields assigned, object returned
When new ShipDestroyed(...) runs, which constructor executes first, which one receives the message, and where does control return?

The sequence has three steps in the source's description. First, the caller creates the object and supplies four values. Second, the constructor calls super(message), so the superclass receives only the message. Third, the constructor stores the remaining values in the object's own fields. The message travels up the chain, while the ship and the coordinates stay with the new object.

Where the Extra Information Lives

A custom exception can do more than carry a message. The ShipDestroyed class declares instance variables for the ship that was destroyed and the location where it was destroyed. These give the error context beyond a text description. The constructor parameters carry the data in, and the fields keep it for later use. The generated code below shows one way to write this class, following the pattern the source describes. The coordinates are represented as two integers here, which is an assumption made for illustration.

java
Notes on the code
  • private Ship ship and the two int fields are instance variables that belong to each object.
  • The constructor receives four parameters: the message and three values for the ship and location.
  • super(message) is the only line that involves the superclass.
  • The three assignments store the remaining values in the object's own fields.
shipthe destroyed shipmessagehanded to the superclassxhorizontal positionyvertical position
What does a single ShipDestroyed object hold: the fields it declares, and the message that went to the superclass instead?

The diagram shows the object's contents after construction. Each box in the own fields group is a value the object holds. The message is shown separately because it is passed to the superclass rather than stored in a field of ShipDestroyed.

Tracing a Construction Step by Step

Worked example

Constructing one ShipDestroyed exception

Trace what happens for the call new ShipDestroyed("Ship hit at edge", alien, 12, 4), where alien is an existing Ship object. This example is generated for illustration.

  1. 1
    Pass the arguments

    The caller supplies four values: the message "Ship hit at edge", the ship object alien, and the coordinates 12 and 4.

  2. 2
    Call the superclass

    The first statement, super(message), sends only "Ship hit at edge" to the RuntimeException constructor. The superclass receives no ship and no coordinates.

  3. 3
    Assign the ship

    this.ship = ship stores the reference to alien in the ship field of the new object.

  4. 4
    Assign the coordinates

    this.x = x stores 12 and this.y = y stores 4. The object now holds the ship and its position.

Result

The exception carries the text "Ship hit at edge" through the superclass, and its own fields hold alien, 12, and 4 for later use.

Code walkthrough
ShipDestroyed e = new ShipDestroyed("Ship hit at edge", alien, 12, 4);
  1. 1
    The new keyword creates an object and calls the ShipDestroyed constructor with four arguments.
  2. 2
    Inside the constructor, the parameter message holds "Ship hit at edge" and the parameter ship holds alien.
  3. 3
    super(message) runs before any other statement in the constructor and hands the text to the superclass.
  4. 4
    The parameters ship, x, and y are assigned to the fields with the same names, using this to distinguish field from parameter.
  5. 5
    The variable e now refers to the finished object, which holds the ship and position in its own fields.

Mistakes Beginners Make with the Constructor

  • Common mistake

    Storing the message in a subclass field instead of calling super(message)

    What it looks like
    public ShipDestroyed(String message, Ship ship, int x, int y) { this.message = message; this.ship = ship; ... }
    Why it fails

    The source says the constructor forwards the message to the superclass, which is responsible for setting up the error message. A message kept only in a subclass field never reaches the superclass.

    Do this instead

    Call super(message) as the first statement, and store only the extra values such as the ship and location in the object's own fields.

  • Common mistake

    Assuming the parameter and the field with the same name hold different values

    What it looks like
    this.x = x;
    Why it fails

    The source's trace warns that reading names can diverge from what the code does. Here the right-hand x is the parameter, and this.x is the field.

    Do this instead

    Read the right-hand side as the parameter passed in, and the left-hand side with this as the field that keeps it.

  • Common mistake

    Expecting the ship and coordinates to be sent up to the superclass

    Why it fails

    super(message) passes only the message. The other values are assigned to fields in the subclass.

Before
public class ShipDestroyed extends RuntimeException {
    private String message;
    private Ship ship;

    public ShipDestroyed(String message, Ship ship) {
        this.message = message;
        this.ship = ship;
    }
}

The message is stored in a field of ShipDestroyed, and the superclass is never given the message.

After
public class ShipDestroyed extends RuntimeException {
    private Ship ship;

    public ShipDestroyed(String message, Ship ship) {
        super(message);
        this.ship = ship;
    }
}

The message is forwarded with super(message), and the subclass keeps only the extra information.

Practice Writing a Custom Exception

EASY

Write a custom exception class named UnknownCommand that extends Exception. Its constructor should take a String message and a String command. Forward the message to the superclass, and store the command in an instance variable. Before you write it, predict on paper which superclass you chose and what the constructor receives.

Hints
  • Start with the same minimum shape as ParseError: a class declaration with extends, and a constructor that calls super(message).
  • Add one private String field for the command, and assign it from the parameter in the constructor body after super(message).
  • Trace your constructor line by line and check that the message never gets stored in a field of your class.

Key Takeaways

  • A custom exception class extends Exception or RuntimeException, and its name describes the error.
  • The constructor forwards the error message to the superclass with super(message), which is responsible for setting up the message.
  • Extra information such as a ship and its location is kept in instance variables assigned from constructor parameters.
  • Tracing the constructor line by line shows which values go to the superclass and which stay in the object's own fields, and this is where readings of the code can diverge from what it does.