Errors & Exceptions
Learning Objectives
- Understand what is meant by an "exception" within an application
- Understand the distinction between checked and unchecked exceptions
- Understand how to handle exceptions in Java using the
try
andcatch
syntax
Error Handling
When building applications, things can go wrong either at compile time or runtime. It is best practice to handle scenarios where our code does not behave as expected. This is called exception handling.
Thankfully, Java contains syntax for catching and reacting to exceptions:
- The try statement allows you to define a block of code to be tested for errors while it is being executed.
- The catch statement allows you to define a block of code to be executed, if an error occurs in the try block.
try {
// Block of code to try
}
catch(Exception e) {
// Block of code to handle errors
}
e
. So, rather than simply breaking the app, we can add business logic to decide what to do next if we so choose. For example, if we are trying to load a file, but we get an exception because the file doesn't actually exist the specified path, we might try to load a file from a different location, or just create a new file and go from there. The point is, it gives you, the programmer, control over the next steps when things go wrong.
Checked and Unchecked Exceptions
In Java, there 2 basic kinds of exceptions: - Checked exceptions: These are forseeable exceptions, such as trying to reading a file that doesn't exist etc. - Unchecked exceptions: These represent errors in application logic, such as reading index 5 in an array that only has 5 elements (index 5 represents the 6th element, which doesn't exist in this example).
Checked Exceptions
Take reading a file as an example of a checked exception - You need to handle this kind of exception at compile time, otherwise your code will not compile for you.
Checked exceptions represent errors outside the control of the program - they can be foreseen, and so they are 'checked for' at compile time. For example, if you are reading a file, Java knows there is a possibility that the file will not exist, and so it requires you to handle a possible FileNotFound
exception. Most IDEs, including InjelliJ, highlight these issue for you in realtime (as you program) and suggest solutions, such as either throwing the exception up the call chain to the method that is calling the current one by using the throws
keyword (which is like kicking the can down the road. Someone will have to deal with it eventually...), or adding a try/catch block to deal with it directly.
Option 1: Try Catch
Here, we handle a FileNotFound exception directly, using a try catch block:
File file = new File("file.txt");
try {
FileInputStream stream = new FileInputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Option 2: Throw it 'Up the Call Chain'
In this example, instead of handling it directly, we use the throws
keyword to declare to the method calling this one that it throws
an exception of a particular type (in this case, a FileNotFoundException
) - this shifts the onus of responsibility onto the calling method. It's a bit like kicking the can down the road; eventually, someone will have to deal with it:
public void readFile() throws FileNotFoundException {
File file = new File("file.txt");
FileInputStream stream = new FileInputStream(file);
}
Unchecked Exceptions
If a program throws an unchecked exception, it reflects some error inside the program logic. For example, if we divide a number by 0, Java will throw ArithmeticException
:
System.out.println(10 / 0);
Having considered these fundamentals of exception handling, we are ready to take a look at some tasks which involve working with checked exceptions, such as reading and writing files. That will be the subject of our next lesson.