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:

exception chaining rule

So remember this rule when designing and coding your program.

 

References:

 

Other Java Exception Handling Tutorials:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Add comment

   


Comments 

#3noura2021-03-16 18:34
public class Pyramid {
public static void main(String[] args) {
int t = 0;
for(int i = 1; i < 5; i++)
{
int d = 1;
for (int j = 1; j < i; j++)
d *= 10;
t += i * d;
System.out.println(t);
}
}
}
Quote
#2Yogesh2019-03-18 12:05
Page contains too many as...but i was searching aa lot for the clarification given on this blog thanks.
Quote
#1AKSHAY SHARMA2018-10-11 05:10
Really Good this tutorial is and i appreciate the effort of the writer who has written this blog . My concept is really clear now about reading the exception stack trace .
Quote