Java Intermediate: Objects, Collections and Errors
Exceptions
In this lesson you will
- Catch exceptions with try, catch and finally
- Explain checked and unchecked exceptions
- Throw and define your own exceptions and use try-with-resources
Introduction
Things go wrong: a file is missing, a number is divided by zero, a value is null. Java reports these problems as exceptions. If nothing handles an exception, the program stops with an error. If you catch it, your program can respond sensibly and carry on.
What an uncaught exception looks like
Java
public class Main {
public static void main(String[] args) {
int[] numbers = {1, 2, 3};
System.out.println("Before");
System.out.println(numbers[5]);
System.out.println("After");
}
}BeforeThe program printed Before and then crashed. On your screen you would also see a message like Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3, with a stack trace listing which methods were running. After never printed.
try and catch
Put risky code in try. If an exception occurs, Java skips the rest of the try block and runs the matching catch.
Java
public class Main {
public static void main(String[] args) {
int[] numbers = {1, 2, 3};
try {
System.out.println(numbers[5]);
System.out.println("not reached");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Caught: " + e.getMessage());
}
System.out.println("The program carries on");
}
}Caught: Index 5 out of bounds for length 3
The program carries onCommon exceptions: NullPointerException, NumberFormatException (such as Integer.parseInt("abc")), ArithmeticException (integer divide by zero), IllegalArgumentException and IOException.
Quick quiz
What happens to the remaining lines of a try block after an exception is thrown?
Several catches and finally
You can handle different exceptions differently. finally runs always, whether or not an exception occurred. It is the place for cleanup.
Java
public class Main {
static void parse(String text) {
try {
int n = Integer.parseInt(text);
System.out.println(100 / n);
} catch (NumberFormatException e) {
System.out.println("Not a number: " + text);
} catch (ArithmeticException e) {
System.out.println("Cannot divide by zero");
} finally {
System.out.println("Done with " + text);
}
}
public static void main(String[] args) {
parse("20");
parse("abc");
parse("0");
}
}5
Done with 20
Not a number: abc
Done with abc
Cannot divide by zero
Done with 0Put the more specific exceptions first. You can also catch several types in one block with catch (A | B e).
Checked and unchecked exceptions
Java splits exceptions into two kinds.
- Unchecked exceptions (subclasses of
RuntimeException) are usually programming mistakes:NullPointerException,IllegalArgumentException. The compiler does not force you to handle them. - Checked exceptions (other subclasses of
Exception) are problems that can happen even in correct code, likeIOExceptionfor a missing file. The compiler forces you to either catch them or declare them withthrows.
Java
import java.io.IOException;
public class Main {
static void readConfig() throws IOException {
throw new IOException("config file not found");
}
public static void main(String[] args) {
try {
readConfig();
} catch (IOException e) {
System.out.println("Problem: " + e.getMessage());
}
}
}Problem: config file not foundthrows IOException in the method header warns every caller that it might fail. If main neither caught it nor declared it, the code would not compile.
Throwing exceptions
Use throw when your own code detects a problem.
Java
public class Main {
static int percentage(int part, int whole) {
if (whole == 0) {
throw new IllegalArgumentException("whole must not be zero");
}
return part * 100 / whole;
}
public static void main(String[] args) {
System.out.println(percentage(1, 4));
try {
percentage(1, 0);
} catch (IllegalArgumentException e) {
System.out.println("Error: " + e.getMessage());
}
}
}25
Error: whole must not be zeroCustom exceptions
Create your own type by extending Exception (checked) or RuntimeException (unchecked), so callers can catch exactly your problem.
Java
class InsufficientFundsException extends Exception {
private final double shortfall;
InsufficientFundsException(double shortfall) {
super("Short by " + shortfall);
this.shortfall = shortfall;
}
double getShortfall() {
return shortfall;
}
}
class Account {
private double balance = 50;
void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException(amount - balance);
}
balance -= amount;
}
}
public class Main {
public static void main(String[] args) {
Account account = new Account();
try {
account.withdraw(20);
account.withdraw(100);
} catch (InsufficientFundsException e) {
System.out.println(e.getMessage());
System.out.println(e.getShortfall());
}
}
}Short by 70.0
70.0Quick quiz
What is the difference between a checked and an unchecked exception?
try-with-resources
Resources such as files and network connections must be closed. Rather than closing them in finally, declare them in the try brackets, and Java closes them automatically, even if there is an exception. The resource must implement AutoCloseable.
Java
class Connection implements AutoCloseable {
private final String name;
Connection(String name) {
this.name = name;
System.out.println("open " + name);
}
void send(String message) {
System.out.println(name + " sends " + message);
}
@Override
public void close() {
System.out.println("close " + name);
}
}
public class Main {
public static void main(String[] args) {
try (Connection a = new Connection("A"); Connection b = new Connection("B")) {
a.send("hello");
b.send("world");
throw new IllegalStateException("something broke");
} catch (IllegalStateException e) {
System.out.println("caught: " + e.getMessage());
}
}
}open A
open B
A sends hello
B sends world
close B
close A
caught: something brokeNotice that both connections were closed (in reverse order) before the catch ran. Files, database connections and Scanner should always be opened this way.
Good habits
- Catch the most specific exception you can handle. Avoid
catch (Exception e)unless you really mean it. - Never leave a
catchblock empty. At least log the problem. - Use exceptions for exceptional situations, not for normal flow.
- Include helpful messages when you throw.
Try it yourself
On your computer, write a method static int safeParse(String text, int fallback) that returns the integer in the text, or the fallback if the text is not a valid number. Test it with "42", "abc" and "".
Summary
- An uncaught exception stops the program.
try/catchhandles it, andfinallyalways runs. - Unchecked exceptions (RuntimeException) are mistakes. Checked exceptions must be caught or declared with
throws. - Use
throw new ...to signal problems and define custom exception classes by extendingException. - try-with-resources closes
AutoCloseableresources automatically.
Lesson complete
+20 XP
Nice work. Keep going while it is fresh.
Sources and further reading