Exceptions
An exception is how Java reports that something went wrong while the program was running: an index past the end of an array, a number that isn't a number, a file that doesn't exist.
public class Main {
public static void main(String[] args) {
int[] data = {10, 20, 30};
System.out.println("Before");
System.out.println(data[5]);
System.out.println("After"); // never reached
}
}Read the stack trace from the top: the exception's type and message, then lines like at Main.main(Main.java:5), which say where it happened. The program stopped at line 5, so "After" never printed.
try and catch
public class Main {
public static void main(String[] args) {
String[] inputs = {"42", "seven", "12"};
int total = 0;
for (String s : inputs) {
try {
total += Integer.parseInt(s);
} catch (NumberFormatException e) {
System.out.println("Skipping '" + s + "': not a number");
}
}
System.out.println("Total: " + total);
}
}When code inside try throws, Java jumps straight to the matching catch, and the program carries on after it instead of crashing.
Several catches, and finally
public class Main {
static int divide(String a, String b) {
try {
return Integer.parseInt(a) / Integer.parseInt(b);
} catch (NumberFormatException e) {
System.out.println("Bad number: " + e.getMessage());
} catch (ArithmeticException e) {
System.out.println("Maths error: " + e.getMessage());
} finally {
System.out.println("(finished " + a + " / " + b + ")");
}
return 0;
}
public static void main(String[] args) {
System.out.println(divide("10", "2"));
System.out.println(divide("10", "zero"));
System.out.println(divide("10", "0"));
}
}Each catch handles one kind of exception. The finally block runs whether or not anything went wrong, even after a return, which makes it the place for clean-up.
Throwing exceptions
public class Main {
static void setAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("Age can't be negative: " + age);
}
System.out.println("Age set to " + age);
}
public static void main(String[] args) {
setAge(21);
try {
setAge(-3);
} catch (IllegalArgumentException e) {
System.out.println("Caught: " + e.getMessage());
}
}
}throw raises an exception yourself, when a method is given something it can't work with.
Checked and unchecked
| Unchecked | Checked | |
|---|---|---|
| extends | RuntimeException | Exception |
| examples | NullPointerException, IllegalArgumentException, ArithmeticException | IOException, FileNotFoundException |
| the compiler | lets you ignore them | insists you catch them or declare them with throws |
| usually means | a bug in the program | a problem outside the program's control |
void loadSettings() throws IOException { // callers must now handle IOException
...
}An exception of your own
class InsufficientFundsException extends Exception {
InsufficientFundsException(String message) {
super(message);
}
}
class Account {
private double balance = 100;
void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException("Balance is " + balance + ", tried to take " + amount);
}
balance -= amount;
}
}
public class Main {
public static void main(String[] args) {
Account acct = new Account();
try {
acct.withdraw(30);
acct.withdraw(500);
} catch (InsufficientFundsException e) {
System.out.println("Refused: " + e.getMessage());
}
}
}Because it extends Exception, it's a checked exception: the compiler makes every caller of withdraw decide what to do when the money runs out.
try-with-resources
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
public class Main {
public static void main(String[] args) {
String file = "line one\nline two\nline three";
try (BufferedReader reader = new BufferedReader(new StringReader(file))) {
String line;
int n = 1;
while ((line = reader.readLine()) != null) {
System.out.println(n++ + ": " + line);
}
} catch (IOException e) {
System.out.println("Could not read: " + e.getMessage());
}
}
}Anything opened in the brackets after try, such as a file, a network connection or a database connection, is closed automatically at the end, even if an exception is thrown. (A StringReader stands in for a real file here, because the code runner has no files to read.)