- Details
- Written by Nam Ha Minh
- Last Updated on 10 July 2019   |   Print Email
This Java exception tutorial helps you understand the concept of exception stack trace in Java and how to analyze an exception stack trace to detect bugs.In this tutorial, we use the example in the article
Understanding Java Exception Chaining with Code Examples. So kindly refer to that article while reading this one.
1. Analyzing an Exception Stack Trace
Look at the output of the
StudentProgramexample:
StudentException: Error finding students
at StudentManager.findStudents(StudentManager.java:13)
at StudentProgram.main(StudentProgram.java:9)
Caused by: DAOException: Error querying students from database
at StudentDAO.list(StudentDAO.java:11)
at StudentManager.findStudents(StudentManager.java:11)
... 1 more
Caused by: java.sql.SQLException: Syntax Error
at DatabaseUtils.executeQuery(DatabaseUtils.java:5)
at StudentDAO.list(StudentDAO.java:8)
... 2 more
By examining this information we can find the root cause of the problem in order to fix bugs. In this exception stack trace, you see a list of chained exceptions which is sorted by the exception at the highest level to the one at the lowest level. This forms a stack like a stack of cards.In each trace, we see the exception type (exception class name) along with the message:
StudentException: Error finding students
We also know the class, method and line number that raises the exception:
at StudentManager.findStudents(StudentManager.java:13)
This line tells us that the
StudentException was thrown at line 13 in the method
findStudents() of the class
StudentManager.And what causes the
StudentException? Look at the next trace, we see:
Caused by: DAOException: Error querying students from database
That means the
StudentException is caused by the
DAOException which is thrown at line 11 in the method
list() of the
StudentDAO class.Continue investigating further until the last exception in the trace, we see that the
SQLException is actually the root cause and the actual place that sparks the exception is at line 5 in the method
executeQuery() of the
DatabaseUtils class:
Caused by: java.sql.SQLException: Syntax Error
at DatabaseUtils.executeQuery(DatabaseUtils.java:5)
And here’s code of the
DatabaseUtils class:
import java.sql.*;
public class DatabaseUtils {
public static void executeQuery(String sql) throws SQLException {
throw new SQLException("Syntax Error");
}
}
So basically that’s how we analyze the exception stack trace to find the root cause of the bug. The root cause is always at the bottom of the stack.
2. Preventing Exceptions Lost
Chaining exceptions together is a good practice, as it prevents exceptions from losing in the stack trace. Let’s modify the
StudentDAO class like this:
import java.sql.*;
public class StudentDAO {
public void list() throws DAOException {
try {
DatabaseUtils.executeQuery("SELECT");
} catch (SQLException ex) {
throw new DAOException("Error querying students from database");
}
}
}
Here we remove the
SQLExceptioninstance (
ex) from the
DAOException’s constructor. Let’s compile and run the
StudentProgram again, we would get the following output:
StudentException: Error finding students
at StudentManager.findStudents(StudentManager.java:13)
at StudentProgram.main(StudentProgram.java:11)
Caused by: DAOException: Error querying students from database
at StudentDAO.list(StudentDAO.java:11)
at StudentManager.findStudents(StudentManager.java:11)
... 1 more
By comparing this exception stack trace with the previous one, we see that the
SQLException disappears, right? That means the
SQLException is lost in the stack trace though it is actually the root cause. When this happens, it’s hard to detect bugs exactly as the truth is hidden.So you understand the importance of chaining exceptions together, don’t you?
3. Working with Exception Stack Trace
Besides the
printStackTrace() method which prints out the detail exception stack trace, the
Throwable class also provides several methods for working with the stack trace. Here I name a few.
- The printStackTrace(PrintStream) method writes the stack trace to a file stream. For example:
} catch (StudentException ex) {
try {
PrintStream stream = new PrintStream(new File("exceptions1.txt"));
ex.printStackTrace(stream);
stream.close();
} catch (FileNotFoundException fne) {
fne.printStackTrace();
}
}
- The printStackTrace(PrintWriter) method writes the stack trace to a file writer. For example:
} catch (StudentException ex) {
// print stack trace to a PrintWriter
try {
PrintWriter writer = new PrintWriter(new File("exceptions2.txt"));
ex.printStackTrace(writer);
writer.close();
} catch (FileNotFoundException fne) {
fne.printStackTrace();
}
}
- The getStackTrace() method returns an array of StackTraceElement objects which allows us to access the stack trace programmatically. Here’s an example:
} catch (StudentException ex) {
StackTraceElement[] stackTrace = ex.getStackTrace();
for (StackTraceElement trace : stackTrace) {
String traceInfo
= trace.getClassName() + "."
+ trace.getMethodName() + ":" + trace.getLineNumber()
+ "(" + trace.getFileName() + ")";
System.out.println(traceInfo);
}
}
Consult the
Javadoc of the Throwable class to see more methods like
fillInStackTrace(),
setStackTrace(), etc.
4. A good practice about exception handling
Don’t handle exceptions in the intermediate layers, because code in the middle layers is often used by code in the higher layers. It’s responsibility of the code in the top-most layer to handle the exceptions. The top-most layer is typically the user interface such as command-line console, window or webpage. And typically we handle exceptions by showing a warning/error message to the user.This good practice is illustrated by the following picture:
So remember this rule when designing and coding your program.
References:
Other Java Exception Handling Tutorials:
About the Author:
Nam Ha Minh is certified Java programmer (SCJP and SCWCD). He started programming with Java in the time of Java 1.4 and has been falling in love with Java since then. Make friend with him on
Facebook and watch
his Java videos you YouTube.