Understanding Exception Handling in Java
This article explains Java's exception handling mechanism, covering try‑catch‑finally structures, the distinction between checked and unchecked exceptions, practical code examples for file I/O and custom exceptions, and best‑practice guidelines for designing robust error‑handling logic.
Java's exception handling mechanism, largely inherited from C++, allows developers to separate error‑prone code from normal execution flow using special exception objects that can be thrown and caught.
When an exception occurs, the runtime throws an object; the call stack unwinds until it reaches a matching catch block, where the programmer can decide how to respond—e.g., notifying the user, handling the error, continuing execution, or terminating the program. A finally block, if present, runs regardless of whether an exception was thrown.
The article distinguishes two major categories of exceptions: unchecked (subclasses of Error and RuntimeException ) that usually indicate programming mistakes and need not be declared, and checked exceptions (subclasses of Exception other than RuntimeException ) that represent recoverable conditions such as IOException or MalformedURLException and must be declared or handled.
Example 1 shows a typical try‑catch‑finally pattern for reading a text file, handling possible IOException , printing a stack trace, and ensuring the file is closed in the finally block:
BufferedReader br = new BufferedReader(new FileReader("file.txt"));
try {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append("\n");
line = br.readLine();
}
String everything = sb.toString();
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO problem");
} finally {
br.close();
}Example 2 introduces a Battery class with methods chargeBattery and useBattery . The useBattery method demonstrates nested try‑catch handling, calling a helper test method that throws an Exception when a negative value is supplied:
public class Test {
public static void main(String[] args) {
Battery aBattery = new Battery();
aBattery.chargeBattery(0.5);
aBattery.useBattery(-0.5);
}
}
class Battery {
/** increase battery */
public void chargeBattery(double p) {
if (this.power + p < 1.) {
this.power = this.power + p;
} else {
this.power = 1.;
}
}
/** consume battery */
public boolean useBattery(double p) {
try {
test(p);
} catch (Exception e) {
System.out.println("catch Exception");
System.out.println(e.getMessage());
p = 0.0;
}
if (this.power >= p) {
this.power = this.power - p;
return true;
} else {
this.power = 0.0;
return false;
}
}
private void test(double p) throws Exception {
if (p < 0) {
Exception e = new Exception("p must be positive");
throw e;
}
}
private double power = 0.0; // percentage of battery
}The article also shows how to define a custom exception by extending Exception , providing both a no‑argument constructor and one that accepts a message string:
class BatteryUsageException extends Exception {
public BatteryUsageException() {}
public BatteryUsageException(String msg) {
super(msg);
}
}Finally, it warns that excessive or overly fine‑grained exception handling can clutter large projects, and advises careful design of error‑handling strategies to keep code maintainable.
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.