We’ll spend the next few lessons learning about Java exceptions. Errors are a normal part of programming, and Java provides nice ways for handling them. Let’s learn more!
It’s natural to make mistakes when you write computer programs. But even well-designed programs may encounter errors!
Imagine the following scenario.
You design an app that prompts the user to enter a number that you plan to use in a mathematical calculation.
What you receive is a String
, so you need to convert it to an Integer
.
What could go wrong?
Let’s find out!
What is happening here?
Let’s examine the documentation for Integer.parseInt
to find out.
try-catch
try-catch
In Java, when code that we write or call encounters an error, it can throw an Exception
.
Over the next few lessons we’ll explore Java’s error-handling mechanisms, including types of exceptions and how to design and throw them in our own code.
But let’s start at looking at how to handle exceptions that we might encounter.
To do this we use a new Java programming construct: try-catch
.
Let’s see how that works!
try-catch
consists of two or more code blocks.
First, the try
block, containing the code that might throw an exception.
Second, one or more catch
blocks that handle various kinds of exceptions that the code might throw.
Let’s look at some code that can generate several kinds of exceptions and see how to handle them:
Create a public class called Catcher
that defines a single class method named catcher
.
catcher
takes, as a single parameter, a Faulter
that has a fault
method.
You should call that fault
method.
If it generates no exception, you should return 0.
If it generates a null pointer exception, you should return 1.
If it throws an illegal argument exception, you should return 2.
If it creates an illegal state exception, you should return 3.
If it generates an array index out of bounds exception, you should return 4.
One of the more difficult parts of exceptions is understanding how code flow changes when an exception is thrown.
When an exception is thrown, Java jumps into the first enclosing catch
block.
This might be in that method, or in calling method, or even in the caller’s caller or higher up.
Let’s look at an admittedly contrived example:
Don’t worry if this doesn’t make perfect sense yet—we’ll get lots of practice with this over the next few days!
Provide a public class Catcher
that implements a static
method named retrieveValue
.
retrieveValue
takes an instance of Faulter
and returns the result of calling its getValue
method, which
returns an int
.
Seems simple!
Except there is just one small problem.
Faulter
was implemented by a friend that didn't take CS 124, and so it's getter is pretty buggy.
A lot of the time it will throw an exception rather than return the value.
But you did take CS 124, and so you know how to catch the exception and retry the call to getValue
.
Note that getValue
may fault multiple times before succeeding, and you should retry until it successfully
returns a value.
Let's play a guessing game!
Create a public class name Guesser
that provides a single class method named guessValue
.
guessValue
accepts a single Secret
instance which provides a guess
method that accepts an integer.
If the integer is not the secret value, guess
will throw an exception.
Otherwise, it does not.
guessValue
should return the secret value stored by the Secret
instance.
However, you should only guess values between 0 and 32, inclusive.
If you guess values outside that range, the Secret
instance will break you will no longer be able to extract
the secret!
Also note that some Secret
s will contain invalid values.
If you are presented with a Secret
that does not have a secret value between 0 and 32, inclusive, throw an
assertion error.
(One way to do this is simply assert false
.)
Need more practice? Head over to the practice page.