Imagine a program functioning as a factory. Any defect disrupts the line, much like errors or exceptions, that interrupt the program. Exceptions, or events that disrupt the typical flow provide error details through representative objects in Java.
Java organizes exceptions into a hierarchy. Frequent exceptions include ArithmeticException
, IllegalArgumentException
, NullPointerException
, and IOException
. Our program must handle these to ensure smooth execution.
In Java, we manually throw exceptions using the throw
keyword, much like throwing a ball. This practice is useful for pre-empting known errors. There are different types of exceptions, but here is a small example throwing IllegalArgumentException
when the provided name is null
.
Java1public class Main { 2 static void greet(String name) { 3 if (name == null) { 4 // We cannot greet a person without a name 5 throw new IllegalArgumentException("Name cannot be null"); // Exception thrown here 6 } 7 System.out.println("Hi, " + name); 8 } 9 10 public static void main(String[] args) { 11 greet("John"); // Output: Hi, John 12 greet(null); // throws an Exception and interrupts the program's execution 13 } 14}
We throw an IllegalArgumentException
when name
is null
, interrupting the program's execution.
The try-catch
block manages exceptions. In the code below, an attempt to access a nonexistent array index triggers an ArrayIndexOutOfBoundsException
. Our try-catch
block then catches this exception.
Java1public class Main { 2 public static void main(String[] args) { 3 int[] numbers = {1, 2, 3}; 4 try { 5 System.out.println(numbers[5]); // Attempting to access non-existent index 5 6 // ArrayIndexOutOfBoundsException is triggered, we should handle it to avoid our program to fail 7 } catch (ArrayIndexOutOfBoundsException e) { 8 System.out.println("That index does not exist in the array. Error: " + e.getMessage()); // Handling the exception 9 // e.getMessage() is used to get the exception error message 10 } 11 } 12}
Without a try-catch
block, an exception propagates upward through the method stack until a catch
block catches it. If none is found, the program crashes and the console throws the error.
Take a look at the example:
Java1public class Main { 2 public static void processArray() { 3 int[] numbers = {1, 2, 3}; 4 System.out.println(numbers[5]); // Attempting to access non-existent index 5, throws an ArrayIndexOutOfBoundsException 5 // We do not handle the exception inside `processArray()` procedure, so it goes further 6 } 7 8 public static void main(String[] args) { 9 processArray(); 10 // The exception is not handled neither by `processArray()` nor by `main()`, so the program crashes 11 } 12}
The processArray()
method throws an ArrayIndexOutOfBoundsException
that goes unhandled, resulting in a program crash.
Java classifies exceptions as either RuntimeExceptions
(unchecked) or other Exceptions
(checked). Unchecked exceptions, like the IllegalArgumentException
that we've seen already, don't require the throws
declaration in the function signature. Checked exceptions, however, do require checking at compile time to ensure proper catching or declaration. Here is an example:
Java1public class Main { 2 public static void main(String[] args) { 3 throwRuntimeException(); 4 } 5 6 public static void throwRuntimeException() { 7 throw new RuntimeException("This is a RuntimeException"); // RuntimeException thrown here. Doesn't need to be declared or caught 8 } 9 10 public static void throwException() throws Exception { // Must declare that it throws an Exception 11 throw new Exception("This is an Exception"); // Exception thrown here 12 } 13}
Checked exceptions like Exception
, require either handling or declaration. Unchecked exceptions do not require a throws
declaration.
Great job! We have mastered exceptions in Java, learning to throw and catch exceptions while also understanding unchecked and checked exceptions. Practice these concepts to solidify them. Remember, you develop coding skills through practice. See you in the next lesson!