Exceptions are runtime errors that crash your program if not handled. In test automation, exceptions are constant — elements not found, timeouts, stale references, network failures. Handling them properly is the difference between a flaky test suite and a reliable one.
| Exception | Cause | Automation Context |
|---|---|---|
| NullPointerException | Calling a method on null | Element not found returns null |
| ArrayIndexOutOfBoundsException | Invalid array index | Row/column index exceeds table size |
| NumberFormatException | Parsing invalid number string | Element text contains non-numeric chars |
| ArithmeticException | Division by zero | Dividing by element count that is 0 |
| ClassCastException | Invalid type cast | Casting WebElement to wrong type |
| StringIndexOutOfBoundsException | Invalid string index | Substring on shorter-than-expected text |
public class TryCatch {
public static void main(String[] args) {
// Without try-catch — program crashes
// int result = 10 / 0; // ArithmeticException
// With try-catch — handle gracefully
try {
int result = 10 / 0;
System.out.println("Result: " + result);
} catch (ArithmeticException e) {
System.out.println("Error: Cannot divide by zero");
System.out.println("Message: " + e.getMessage());
}
System.out.println("Program continues after the error");
}
}Error: Cannot divide by zero
Message: / by zero
Program continues after the errorpublic class MultipleCatch {
public static void main(String[] args) {
String[] data = {"100", "abc", null};
for (String item : data) {
try {
int value = Integer.parseInt(item.trim());
System.out.println("Parsed: " + value);
} catch (NumberFormatException e) {
System.out.println("Not a number: \"" + item + "\"");
} catch (NullPointerException e) {
System.out.println("Null value encountered");
}
}
}
}Parsed: 100
Not a number: "abc"
Null value encounteredThe finally block always runs — whether an exception occurred or not. Use it for cleanup: closing browsers, database connections, files.
public class FinallyDemo {
public static void main(String[] args) {
System.out.println("Opening browser...");
try {
System.out.println("Running test...");
int result = 10 / 0; // exception
System.out.println("Test passed"); // skipped
} catch (ArithmeticException e) {
System.out.println("Test failed: " + e.getMessage());
} finally {
System.out.println("Closing browser..."); // always runs
}
}
}Opening browser...
Running test...
Test failed: / by zero
Closing browser...public class ThrowDemo {
// throws — declares that this method might throw an exception
static int divide(int a, int b) throws ArithmeticException {
if (b == 0) {
// throw — creates and throws an exception
throw new ArithmeticException("Divisor cannot be zero");
}
return a / b;
}
static void validateAge(int age) {
if (age < 0 || age > 150) {
throw new IllegalArgumentException("Invalid age: " + age);
}
System.out.println("Valid age: " + age);
}
public static void main(String[] args) {
try {
System.out.println(divide(10, 2)); // 5
System.out.println(divide(10, 0)); // throws exception
} catch (ArithmeticException e) {
System.out.println("Error: " + e.getMessage());
}
try {
validateAge(-5);
} catch (IllegalArgumentException e) {
System.out.println("Error: " + e.getMessage());
}
}
}| Type | Compile Check | Must Handle? | Examples |
|---|---|---|---|
| Checked | Yes — compiler forces handling | Yes (try-catch or throws) | IOException, FileNotFoundException, SQLException |
| Unchecked (Runtime) | No — compiler ignores | No (but recommended) | NullPointerException, ArrayIndexOutOfBounds, NumberFormatException |
public class SafeParsing {
static int safeParseInt(String text, int defaultValue) {
try {
return Integer.parseInt(text.trim());
} catch (NumberFormatException | NullPointerException e) {
return defaultValue;
}
}
public static void main(String[] args) {
System.out.println(safeParseInt("42", 0)); // 42
System.out.println(safeParseInt("abc", 0)); // 0
System.out.println(safeParseInt(null, -1)); // -1
System.out.println(safeParseInt(" 7 ", 0)); // 7
}
}Q: What is the difference between throw and throws?
A: throw is used inside a method body to actually create and throw an exception object: throw new Exception("message"). throws is used in the method signature to declare that the method might throw certain exceptions: void read() throws IOException. throw is the action, throws is the declaration.
Q: What is the difference between checked and unchecked exceptions?
A: Checked exceptions (IOException, SQLException) are verified at compile time — the compiler forces you to handle them with try-catch or declare them with throws. Unchecked exceptions (NullPointerException, ArrayIndexOutOfBounds) extend RuntimeException and are not checked at compile time. Checked exceptions represent recoverable conditions (file not found); unchecked exceptions usually indicate programming bugs.
Exercise 1: Write a method that takes an array and an index, returns the element at that index. If the index is invalid, catch the exception and return a default value.
Exercise 2: Write a parsePrice method that takes strings like "$29.99", "invalid", "₹1,299", null — and returns the numeric value or 0.0 for invalid inputs. Handle all edge cases.
Exercise 3: Create a custom exception class called TestFailedException that extends RuntimeException. Throw it from a validation method when a condition fails. Catch it in main.