Constructors and Instance Variables
A custom exception class extends Exception or RuntimeException.
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
- Statements in try run until one raises an exception; the rest of try is skipped.
- Python checks the except clauses in order and runs the first one whose type matches.
- If nothing was raised, the else block runs instead.
- 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.
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?
Reveal 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
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.
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.
- The class name
ParseErrordescribes 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.
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.
- 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.
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
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.
- 1Pass the arguments
The caller supplies four values: the message "Ship hit at edge", the ship object alien, and the coordinates 12 and 4.
- 2Call the superclass
The first statement,
super(message), sends only "Ship hit at edge" to theRuntimeExceptionconstructor. The superclass receives no ship and no coordinates. - 3Assign the ship
this.ship= ship stores the reference to alien in the ship field of the new object. - 4Assign the coordinates
this.x= x stores 12 andthis.y= y stores 4. The object now holds the ship and its position.
The exception carries the text "Ship hit at edge" through the superclass, and its own fields hold alien, 12, and 4 for later use.
ShipDestroyed e = new ShipDestroyed("Ship hit at edge", alien, 12, 4);- 1The new keyword creates an object and calls the ShipDestroyed constructor with four arguments.
- 2Inside the constructor, the parameter message holds "Ship hit at edge" and the parameter ship holds alien.
- 3
super(message)runs before any other statement in the constructor and hands the text to the superclass. - 4The parameters ship, x, and y are assigned to the fields with the same names, using this to distinguish field from parameter.
- 5The 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 likepublic ShipDestroyed(String message, Ship ship, int x, int y) { this.message = message; this.ship = ship; ... }Why it failsThe 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 insteadCall 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 likethis.x = x;Why it failsThe source's trace warns that reading names can diverge from what the code does. Here the right-hand x is the parameter, and
this.xis the field.Do this insteadRead 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 failssuper(message)passes only the message. The other values are assigned to fields in the subclass.
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.
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
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 callssuper(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.