Exceptions
In Java, exceptions are a mechanism for handling runtime errors and other exceptional events that can disrupt the normal flow of a program. An exception is an object that represents an error or an unusual condition that occurs during program execution. When an exception is thrown, the normal flow of the program is interrupted, and the control is transferred to an appropriate exception handler.
Types of Exceptions in Java
Java exceptions can be categorized into three main types:
1. Checked Exceptions (Compile Time Exceptions):
-
These exceptions are checked at compile time. A method which uses the
throwskeyword in it's signature MUST be wrapped in an "try-catch block" when called otherwise you can not compile. -
They represent scenarios where a recoverable error might occur, such as issues related to file handling, database access, or network connectivity.
-
Common checked exceptions include
IOException,SQLException, andFileNotFoundException.example: checked exception
import java.io.*;
public class CheckedExceptionExample {
public static void main(String[] args) {
try {
FileReader file = new FileReader("file.txt");
} catch (FileNotFoundException e) {
System.out.println("File not found exception occurred!");
}
}
}- "line 6":
Because theFileReaderclass usesthrowsin the constructor's signature, we need to wrap the object instantiation in an "try-catch block" otherwise the compiler let us not compile the code.
- "line 6":
2. Unchecked Exceptions (Runtime Exceptions):
-
Unchecked exceptions are not checked at compile time but crush your program at runtime. They are usually the result of programming errors, such as logical mistakes or improper use of an API.
-
They are subclasses of
RuntimeExceptionand include exceptions likeNullPointerException,ArrayIndexOutOfBoundsException, andArithmeticException. -
Unchecked exceptions do not need to be declared in the method signature or explicitly caught.
example: unchecked exception
- "line 4:"
- Will crush the program at runtime.
public class UncheckedExceptionExample {
public static void main(String[] args) {
int[] arr = new int[0];
System.out.println(arr[-1]); // This line will cause ArrayIndexOutOfBoundsException
}
}- "line 4-5":
try {}
The statement which would throw an exception is wrapped in an try block. - "line 6-8":
catch {}
TheRuntimeExceptionexception is caught and it's reference saved in the variablee.
The error message is printed to the terminal and the code can continues without crashing.
public class UncheckedExceptionExample {
public static void main(String[] args) {
int[] arr = new int[0];
try {
System.out.println(arr[-1]);
} catch (RuntimeException e) {
System.out.println(e.getMessage());
}
System.out.println("The program did not crash!");
}
}Index -1 out of bounds for length 0
The program did not crash!
Process finished with exit code 0 - "line 4:"
3. Errors:
-
Errors are not exceptions but rather serious problems that indicate a failure in the Java runtime environment (JVM).
-
Errors are usually not meant to be caught or handled, as they represent system-level issues like
OutOfMemoryErrororStackOverflowError. -
These errors are subclasses of the
Errorclass and should not be handled programmatically.example: error
public class ErrorExample {
public static void main(String[] args) {
recursiveMethod(); // This will cause a StackOverflowError due to infinite recursion
}
public static void recursiveMethod() {
recursiveMethod();
}
}
Exception Handling Mechanism
Java uses the following keywords to handle exceptions:
-
try: Used to specify a block of code that may throw an exception. -
catch: Used to specify a block of code that will execute if a particular exception is thrown in thetryblock. -
finally: Used to specify a block of code that will always execute, regardless of whether an exception is thrown or not. It is generally used to release resources like closing files or database connections. -
throw: Used to explicitly throw an exception. -
throws: Used in the method signature to declare that a method may throw one or more exceptions.example: exception handling
import java.io.*;
public class ExceptionHandlingExample {
public static void main(String[] args) {
try {
// This might throw a FileNotFoundException
FileReader file = new FileReader("nonexistentfile.txt");
BufferedReader fileInput = new BufferedReader(file);
// Read and print the first line of the file
System.out.println(fileInput.readLine());
} catch (FileNotFoundException e) {
// This block handles FileNotFoundException
System.out.println("File not found. Please check the file path.");
} catch (IOException e) {
// This block handles other IOExceptions
System.out.println("An IOException occurred while reading the file.");
} finally {
// This block always executes, whether an exception occurs or not
System.out.println("Executing the finally block.");
}
}
}
Creating Custom Exceptions
Java allows developers to define their own custom exceptions by extending the Exception class or RuntimeException class.
NOTE: This are only examples to demonstrate the use of "custom exceptions",
You should always try to avoid throwing exceptions and rather fix your code in a way that it does not crash!
example: custom "checked exception"
// Creating a custom checked exception
class CustomCheckedException extends Exception {
public CustomCheckedException(String message) {
super(message);
}
}
public class CustomExceptionExample {
// Method that throws a custom checked exception
public static void checkAge(int age) throws CustomCheckedException {
if (age < 18)
throw new CustomCheckedException("Age is below 18!");
}
public static void main(String[] args) {
try {
checkAge(16); // This will throw the custom checked exception
} catch (CustomCheckedException e) {
System.out.println(e.getMessage());
}
System.out.println("Program did not crash!");
}
}
- "line 2-6": defining the "custom exception class"
Defines theCustomCheckedException(the name is arbitrary) subclass by extending theExceptionclass. - "line 10":
- Because the keyword
throwsis used in the method signature, the method needs to be always wrapped in an "try-catch block" when called. - Need to have a
throw new+CUSTOM_EXCEPTION_CLASSstatement.
- Because the keyword
- "line 12":
- Throw (create an instance of the object) the
CustomCheckedExceptionobject with messageAge is below 18!.
- Throw (create an instance of the object) the
- "line 17":
Because thecheckAgemethod uses throws, it needs to be always wrapped in an try-catch block even if it would not throw an exception (e.g.:age >= 18). - "line 18":
Thecatchblock runs only if there was an exception in thetryblock.
Age is below 18!
Program did not crash!
Process finished with exit code 0
example: custom "unchecked exception"
class CustomUncheckedException extends RuntimeException {
public CustomUncheckedException(String message) {
super(message);
}
}
public class CustomExceptionExample {
// Method that throws a custom checked exception
public static void checkAge(int age) throws CustomUncheckedException {
if (age < 18)
throw new CustomUncheckedException("Age is below 18!");
}
public static void main(String[] args) {
checkAge(0); // Crush program but would pass if 18 or higher
try {
checkAge(16); // This will throw the custom checked exception
} catch (CustomUncheckedException e) {
System.out.println(e.getMessage());
}
System.out.println("Program did not crash!");
}
}
This example works in the same way as the other example above "checked exceptions", but with a few differences!
- "line 2":
Note: in this example we are extending theRuntimeExceptionclass. - "line 15":
Note: The method dose not need to be wrapped in an "try-catch block"! The compiler compiles the code but it will crush at runtime because of the uncaught error, none of the code after is executed.
- "line 17":
Assuming the argument of thecheckAge()method on "line 15" would have been18or higher, than the program would not have crushed at runtime.
The argument is still to low and an exception is thrown, but because it will be caught on in the next block, the program dose not crash.
Age is below 18! #// from 'line 17'
Program did not crash! #// from 'line 21'
Process finished with exit code 0
Exception Hierarchy
All exception classes in Java are part of a hierarchical structure:
Throwable:
The root class for all errors and exceptions in Java. It has two main subclasses:Exception: Represents conditions that a reasonable application might want to catch.Error: Represents serious issues that a program should not try to catch (e.g., system failures).
Exception:
has two main categories:- Checked exceptions: Direct subclasses of
Exception(excludingRuntimeExceptionand its subclasses). - Unchecked exceptions: Subclasses of
RuntimeException.
- Checked exceptions: Direct subclasses of
RuntimeException:
Base class for unchecked exceptions, such asNullPointerExceptionandClassCastException.
Catch and the Exception class hierarchy
Start with the less precise exception object, because only the first true catch block is executed. Which can lead to a lose of information (e.g. .getMessage()).