Analyzing Stack Trace

Introduction

Stack trace shows the sequence of method calls that led to an exception. Essential for debugging.


What is Stack Trace?

Stack trace = list of method calls from the point where exception occurred back to the beginning.

Shows:

  • Exception type
  • Error message
  • Method call sequence
  • Line numbers
  • File names

Simple Example

public class Main {
    static void method3() {
        int result = 10 / 0;  // Exception here
    }

    static void method2() {
        method3();
    }

    static void method1() {
        method2();
    }

    public static void main(String[] args) {
        method1();
    }
}

Stack Trace Output:

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at Main.method3(Main.java:3)
    at Main.method2(Main.java:7)
    at Main.method1(Main.java:11)
    at Main.main(Main.java:15)

Reading Stack Trace

java.lang.ArithmeticException: / by zero
    at ClassName.methodName(FileName.java:lineNumber)

Parts:

  1. Exception type: ArithmeticException
  2. Message: / by zero
  3. Location: ClassName.methodName
  4. File: FileName.java
  5. Line: lineNumber

Stack Trace Direction

Read from top to bottom:

  • Top = where exception occurred (most recent)
  • Bottom = where program started (oldest)
Exception in thread "main" java.lang.NullPointerException
    at MyClass.method3(MyClass.java:15)  ← Exception here!
    at MyClass.method2(MyClass.java:11)  ← Called by method2
    at MyClass.method1(MyClass.java:7)   ← Called by method1
    at MyClass.main(MyClass.java:3)      ← Started from main

printStackTrace() Method

public class Main {
    public static void main(String[] args) {
        try {
            int result = 10 / 0;
        } catch (ArithmeticException e) {
            // Print stack trace
            e.printStackTrace();
        }
        System.out.println("Program continues");
    }
}

Getting Stack Trace Elements

public class Main {
    public static void main(String[] args) {
        try {
            int result = 10 / 0;
        } catch (ArithmeticException e) {
            // Get stack trace as array
            StackTraceElement[] elements = e.getStackTrace();

            for (StackTraceElement element : elements) {
                System.out.println("Class: " + element.getClassName());
                System.out.println("Method: " + element.getMethodName());
                System.out.println("Line: " + element.getLineNumber());
                System.out.println("File: " + element.getFileName());
                System.out.println();
            }
        }
    }
}

Nested Method Calls

class Calculator {
    int divide(int a, int b) {
        return a / b;  // Line 3
    }
}

class MathService {
    Calculator calc = new Calculator();

    int calculate(int x, int y) {
        return calc.divide(x, y);  // Line 10
    }
}

public class Main {
    public static void main(String[] args) {
        MathService service = new MathService();
        service.calculate(10, 0);  // Line 17
    }
}

Stack Trace:

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at Calculator.divide(Calculator.java:3)
    at MathService.calculate(MathService.java:10)
    at Main.main(Main.java:17)

Common Stack Traces

NullPointerException:

java.lang.NullPointerException
    at MyClass.processString(MyClass.java:25)
    at MyClass.main(MyClass.java:10)

Analysis: Line 25 in processString method has null reference.

ArrayIndexOutOfBoundsException:

java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3
    at MyClass.printArray(MyClass.java:15)
    at MyClass.main(MyClass.java:7)

Analysis: Line 15 accessing array with invalid index 5.

NumberFormatException:

java.lang.NumberFormatException: For input string: "abc"
    at Integer.parseInt(Integer.java:652)
    at MyClass.convertNumber(MyClass.java:20)
    at MyClass.main(MyClass.java:8)

Analysis: Line 20 trying to convert “abc” to integer.


Analyzing Complete Example

class Student {
    String name;

    void setName(String name) {
        this.name = name.toUpperCase();  // Line 5
    }
}

class StudentService {
    void processStudent(Student student, String name) {
        student.setName(name);  // Line 11
    }
}

public class Main {
    public static void main(String[] args) {
        Student student = new Student();
        StudentService service = new StudentService();
        service.processStudent(student, null);  // Line 18
    }
}

Stack Trace:

Exception in thread "main" java.lang.NullPointerException
    at Student.setName(Student.java:5)
    at StudentService.processStudent(StudentService.java:11)
    at Main.main(Main.java:18)

Analysis:

  1. Exception at Student.setName line 5
  2. Called from StudentService.processStudent line 11
  3. Called from Main.main line 18
  4. Problem: null passed to setName, calling toUpperCase() on null

Caused By

Shows original cause of exception.

import java.io.*;

public class Main {
    static void readFile() throws IOException {
        FileReader fr = new FileReader("nonexistent.txt");
    }

    public static void main(String[] args) {
        try {
            readFile();
        } catch (IOException e) {
            throw new RuntimeException("Failed to read file", e);
        }
    }
}

Stack Trace:

Exception in thread "main" java.lang.RuntimeException: Failed to read file
    at Main.main(Main.java:11)
Caused by: java.io.FileNotFoundException: nonexistent.txt
    at FileReader.<init>(FileReader.java:72)
    at Main.readFile(Main.java:5)
    at Main.main(Main.java:10)

Logging Stack Trace

import java.io.*;

public class Main {
    public static void main(String[] args) {
        try {
            int result = 10 / 0;
        } catch (Exception e) {
            // Log to console
            System.err.println("Error occurred:");
            e.printStackTrace();

            // Or log to file
            try (PrintWriter pw = new PrintWriter("error.log")) {
                e.printStackTrace(pw);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
}

Stack Trace in Multi-threaded

public class Main {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            int result = 10 / 0;
        });
        t.start();
    }
}

Stack Trace:

Exception in thread "Thread-0" java.lang.ArithmeticException: / by zero
    at Main.lambda$main$0(Main.java:4)
    at java.lang.Thread.run(Thread.java:748)

Note: Shows thread name “Thread-0”.


Practical Debugging

Step 1: Find Exception Type

java.lang.NullPointerException

Means: Using null reference

Step 2: Read Message

Cannot invoke "String.length()" because "str" is null

Means: Variable str is null

Step 3: Find Location

at MyClass.method(MyClass.java:25)

Means: Error at line 25 in method

Step 4: Check Call Chain

at MyClass.method(MyClass.java:25)
at MyClass.process(MyClass.java:15)
at MyClass.main(MyClass.java:7)

Trace: main → process → method


Common Patterns

Pattern 1: Null Pointer

java.lang.NullPointerException

Fix: Check for null before use

Pattern 2: Array Index

java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds

Fix: Check array length

Pattern 3: Number Format

java.lang.NumberFormatException: For input string

Fix: Validate string before parsing

Pattern 4: File Not Found

java.io.FileNotFoundException

Fix: Check file exists


Best Practices

  1. Read from top - exception location
  2. Check line numbers - exact problem spot
  3. Follow call chain - understand flow
  4. Look for “Caused by” - root cause
  5. Log stack traces - for debugging
  6. Don’t ignore - always investigate
  7. Fix root cause - not symptoms

Quick Reference

// Print stack trace
try {
    // code
} catch (Exception e) {
    e.printStackTrace();  // To console
}

// Get stack trace elements
StackTraceElement[] elements = e.getStackTrace();
for (StackTraceElement element : elements) {
    System.out.println(element.getClassName());
    System.out.println(element.getMethodName());
    System.out.println(element.getLineNumber());
}

// Exception info
e.getMessage()      // Error message
e.toString()        // Exception type + message
e.getCause()        // Original exception

Exam Tips

Remember:

  1. Stack trace shows method call sequence
  2. Top = where exception occurred
  3. Bottom = where program started
  4. printStackTrace() prints trace
  5. Line numbers show exact location
  6. Caused by shows root cause
  7. Thread name in multi-threaded
  8. StackTraceElement for details
  9. Read top-down for debugging
  10. Essential for debugging

Common Questions:

  • What is stack trace?
  • How to read stack trace?
  • Direction of stack trace?
  • printStackTrace() method?
  • Getting stack trace elements?
  • What is “Caused by”?
  • Stack trace in multi-threading?
  • How to debug using stack trace?
  • Common patterns?
  • Best practices?