In this module, you will learn about
Throwable
, Exception
, RuntimeException
, and Error,
expressionstry-catch
blocks,Consider the following program.
import java.util.Scanner;
public class DivideByZeroNoExceptionHandling {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Please enter an integer numerator: ");
int numerator = scanner.nextInt();
System.out.print("Please enter an integer denominator: ");
int denominator = scanner.nextInt();
int quotient = quotient(numerator, denominator);
System.out.printf("%nResult: %d / %d = %d%n", numerator, denominator, quotient);
}
public static int quotient(int numerator, int denominator){
return numerator / denominator;
}
}
What will happen if we input 0
as the denominator
?
What if you input a String
instead of an int
?
Our program will throw exceptions!
An exception is an event, which occurs during the execution of a program and disrupts the normal flow of the program's instructions..
Some examples include
An exception is an object that contains
The term exception is shorthand for the phrase "exceptional event".
If no exception handler is found, the program prints the call stack to the console and terminates.
We often use the following expressions.
The call stack is the ordered list of methods that had been called to get to the method where the exception occurred.
Here is a couple of console outputs that show us the call stack from exceptions thrown by our program above.
Please enter an integer numerator: 100
Please enter an integer denominator: 0
Exception in thread "main" java.lang.ArithmeticException: / by zero
at DivideByZeroNoExceptionHandling.quotient(DivideByZeroNoExceptionHandling.java:7)
at DivideByZeroNoExceptionHandling.main(DivideByZeroNoExceptionHandling.java:19)
Please enter an integer numerator: a
Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Scanner.java:864)
at java.util.Scanner.next(Scanner.java:1485)
at java.util.Scanner.nextInt(Scanner.java:2117)
at java.util.Scanner.nextInt(Scanner.java:2076)
at DivideByZeroNoExceptionHandling.main(DivideByZeroNoExceptionHandling.java:14)
We can get the following information from the call stack.
Tip: To understand what broke your code and discover how to fix it, start by looking at the first method you wrote in the call stack.
An exception handler is a block of code that can handle exceptions of one or more types.
The basic structure of an exception handler looks like this:
try {
// The code we want to secure
} catch (ExceptionType exception) {
// The code we want to execute if an exception of type ExceptionType is thrown
} finally {
// The code we want to execute regardless if an exception has been thrown or not
}
It must have exactly one try
block.
It may have zero or more catch
blocks.
It may have at most one finally
block.
However, it must either have a catch
or a
finally
block.
Here is how we can add exception handlers to our previous program.
import java.util.InputMismatchException;
import java.util.Scanner;
public class DivideByZeroExceptionHandling {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
boolean continueLoop = true; // determines if more input is needed
while (continueLoop) {
try { // read two numbers and calculate quotient
System.out.print("Please enter an integer numerator: ");
int numerator = scanner.nextInt();
System.out.print("Please enter an integer denominator: ");
int denominator = scanner.nextInt();
int quotient = quotient(numerator, denominator);
System.out.printf("%nResult: %d / %d = %d%n", numerator, denominator, quotient);
continueLoop = false;
} catch (InputMismatchException e) {
e.printStackTrace();
scanner.nextLine(); // discard input so we can try again
System.out.printf("You must enter integers. Please try again.%n");
} catch (ArithmeticException e) {
e.printStackTrace();
System.out.printf("Cannot divide by 0. Please try again.%n");
}
}
}
public static int quotient(int numerator, int denominator) {
return numerator / denominator;
}
}
try
blockThe first step in constructing an exception handler is to enclose the code that might throw an exception within a try block.
try {
System.out.print("Please enter an integer numerator: ");
int numerator = scanner.nextInt();
// ...
}
If an exception occurs within the try
block, it will be first
passed to its catch
block and then to its finally
block.
catch
blockA catch
block is preceded by a try
block or another catch
block.
Here is an example.
catch (ArithmeticException e) {
// ...
}
A catch
block matches a thrown exception if it is of the type
defined in block or is a subtype of it.
This means that we can write a catch
block that matches all possible exceptions by making it as general as possible.
catch (Exception e) {
// ...
}
Alternatively, we can declare multiple catch
blocks to handle exception types
differently.
catch (InputMismatchException e) {
// ...
}
catch (ArithmeticException e) {
// ...
}
Another option is catching several specific exception types in a single catch
block.
catch (ArithmeticException | InputMismatchException e) {
// ...
}
Here is how our previous example would look like.
import java.util.InputMismatchException;
import java.util.Scanner;
public class DivideByZeroExceptionHandlingSingle {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
boolean continueLoop = true; // determines if more input is needed
while (continueLoop) {
try { // read two numbers and calculate quotient
System.out.print("Please enter an integer numerator: ");
int numerator = scanner.nextInt();
System.out.print("Please enter an integer denominator: ");
int denominator = scanner.nextInt();
int quotient = quotient(numerator, denominator);
System.out.printf("%nResult: %d / %d = %d%n", numerator, denominator, quotient);
continueLoop = false;
} catch (ArithmeticException | InputMismatchException e) {
e.printStackTrace();
scanner.nextLine(); // discard input so we can try again
System.out.printf("Either an ArithmeticException or an InputMismatchException was thrown. Please try again.%n");
}
}
}
public static int quotient(int numerator, int denominator) {
return numerator / denominator;
}
}
try-catch
You can find the solution to this exercise here.
finally
blockThe finally
block always executes after a try
block is executed, which ensures that it is executed even if an
unexpected exception occurs.
The finally
block helps to makes sure that a cleanup
code segment is always executed, and not
accidentally bypassed by a return
, continue
, or break
. Thus,
using a finally
block is always a good practice, even
when no exceptions are anticipated.
The finally block may, however, not execute if the JVM exits while the try or catch code is being executed.
Let us observe the how the following code is executed.
public class FinallyExample {
public static void main(String[] args) {
try {
throwException();
System.out.println("Line after throwException() call");
} catch (Exception e) {
System.out.println("4 Catch block in main()");
}
doesNotThrowException();
}
public static void throwException() throws Exception {
try {
System.out.println("1 Try block in throwException()");
throw new Exception();
} catch (Exception exception) {
System.out.println("2 Catch block in throwException()");
throw exception;
} finally {
System.out.println("3 Finally block in throwException()");
}
}
public static void doesNotThrowException() {
try {
System.out.println("5 Try block in doesNotThrowException()");
} catch (Exception exception) {
System.out.println("6 Catch block in doesNotThrowException()");
} finally {
System.out.println("7 Finally block in doesNotThrowException()");
}
System.out.println("8 End of doesNotThrowException()");
}
}
Now, let us add a finally block to our previous example.
import java.util.InputMismatchException;
import java.util.Scanner;
public class DivideByZeroExceptionHandlingFinally {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
boolean continueLoop = true; // determines if more input is needed
while (continueLoop) {
Integer numerator, denominator, quotient = null;
try { // read two numbers and calculate quotient
System.out.print("Please enter an integer numerator: ");
numerator = scanner.nextInt();
System.out.print("Please enter an integer denominator: ");
denominator = scanner.nextInt();
quotient = quotient(numerator, denominator);
System.out.printf("%nResult: %d / %d = %d%n", numerator, denominator, quotient);
continueLoop = false;
} catch (InputMismatchException e) {
scanner.nextLine(); // discard input so we can try again
e.printStackTrace();
System.out.printf("You must enter integers. Please try again.%n");
} catch (ArithmeticException e) {
e.printStackTrace();
System.out.printf("Cannot divide by 0. Please try again.%n");
} finally {
if (quotient != null)
System.out.printf("OK: Successful division!%n");
else
System.out.printf("ERROR: Unsuccessful division!%n");
}
}
}
public static int quotient(int numerator, int denominator) {
return numerator / denominator;
}
}
finally
block?An actual question from Stackoverflow.
There are 3 permutations of a try...catch...finally block in java.
- try...catch
- try...catch...finally
- try...finally
Once the finally block is executed, control goes to the next line after the finally block. If I remove the finally block and move all its statements to the line after the try...catch block, would that have the same effect as having them in the finally block?
Some appropriate answers to this questions are:
public void myFunc() {
double p = 1.0D;
String str = "bla";
try {
p = Double.valueOf(str);
}
catch (Exception ex){
System.out.println("Exception Happened");
return; //return statement here!!!
} finally{
System.out.println("Finally");
}
System.out.println("After finally");
}
Exception Happened
Finally
try-catch-finally
try
, catch
, and
finally
block print out a message in the console.You can find the solution to this exercise here.
The code below uses the try-with-resources statement.
import java.io.FileWriter;
import java.io.IOException;
public class TryWithResources {
public static void main(String[] args) {
String fileName = "bohemian-rhapsody.txt";
try (FileWriter writer = new FileWriter(fileName)) {
writer.write("Is this the real life?\n");
writer.write("Is this just fantasy?\n");
writer.write("Caught in a landslide\n");
writer.write("No escape from reality\n");
} catch(IOException e){
System.out.println("Could not write to file! :(");
}
}
}
Such an expression can often be used instead of a finally
block.
However, the opened resource must implement the AutoCloseable
interface.