Exercise 2.1: Live Debugging with Breakpoints

Author

Chuck Nelson

Published

October 13, 2025

1 Purpose

The purpose of this exercise is to build on your basic debugging skills by introducing method navigation and the Call Stack. You will learn how to trace your program’s execution path as it moves between different methods. This is a crucial skill for understanding how different parts of your application interact and for isolating logic errors within a complex chain of method calls.

2 What You’ll Accomplish

By the end of this exercise, you will have successfully:

  • Used the Step Into debugger control to enter a method call.
  • Used the Step Out debugger control to return from a method to its caller.
  • Inspected the Call Stack to understand the current execution path of your program.
  • Identified and fixed a logic error by tracing variable state changes through a series of method calls.

This exercise maps to the following program and course learning outcomes:

  • Program Learning Outcomes (PLOs):
    • 2. Use current tools: You will use the advanced features of the VS Code debugger.
    • 5. Implement solutions: You will debug a multi-method Java solution.
    • 6. Maintain environment: You will use the debugger to troubleshoot a logic error.
  • Course Learning Outcomes (CLOs):
    • 1. Develop algorithmic solution: You will trace the logic of an algorithm across multiple methods.
    • 2. Compile, debug, and test: You will use the debugger to find and fix a logic error.
    • 5. Utilize user-defined methods: You will debug the flow of control between user-defined methods.

This exercise will help you develop the following skills and knowledge, which align with the O*NET SOC Code 15-1251.00 for Computer Programmers.

Learning Objective O*NET KSAs Technologies Used
Navigate between methods using ‘Step Into’ and ‘Step Out’. Skills: Programming, Critical Thinking
Abilities: Deductive Reasoning
Program testing software: Symbolic debugger software
Analyze the Call Stack to trace execution flow. Skills: Systems Analysis, Monitoring
Abilities: Information Ordering
Development environment software: VS Code
Isolate and correct a logic error within a method. Skills: Complex Problem Solving, Critical Thinking
Abilities: Problem Sensitivity
Object or component oriented development software: Java

3 Introduction to Deeper Debugging

In the previous exercise, you learned to step through a single method. But most programs are not that simple. They are made of many methods that call each other. When something goes wrong, the error might not be in the method where you see the symptom; it could be in a method that was called several steps earlier.

In this exercise, we’ll explore how to navigate this chain of calls and use the Call Stack to find a bug.

1. Prepare Your Code

To explore method debugging, we need a program with more complexity. First, let’s create the Task and TaskService classes that our App will use.

Create a new file named Task.java in the src/main/java/edu/pstcc/citc directory. This class will represent a single task with a title and a due date.

package edu.pstcc.citc;

public class Task {
    public String title;
    public int daysUntilDue;

    public Task(String title, int daysUntilDue) {
        this.title = title;
        this.daysUntilDue = daysUntilDue;
    }
}

Next, create a new file named TaskService.java in the src/main/java/edu/pstcc/citc directory. This service will contain some (buggy) business logic.

package edu.pstcc.citc;

public class TaskService {

    /**
     * Determines a priority label based on how soon a task is due.
     * There is a logic error in this method.
     */
    public String getPriorityLabel(Task task) {
        String priority = "Low";

        if (task.daysUntilDue < 7) {
            priority = "Medium";
        } else if (task.daysUntilDue < 3) {
            // This logic is flawed!
            priority = "High";
        }
        return priority;
    }
}

Finally, update your App.java file to use these new classes. Our goal is to create a task and determine its priority.

package edu.pstcc.citc;

public class App {
    public static void main(String[] args) {
        TaskService taskService = new TaskService();
        Task urgentTask = new Task("Finish report", 2);

        // We expect this to be "High" priority, but is it?
        String priority = taskService.getPriorityLabel(urgentTask);

        System.out.println("Task: '" + urgentTask.title + "' has priority: " + priority);
    }
}

2. The Bug Hunt

Run the application (mvn exec:java -Dexec.mainClass="edu.pstcc.citc.App"). The output is:

Task: 'Finish report' has priority: Medium

This is wrong! A task due in 2 days should be “High” priority. We need to find out why our logic is failing.

3. Stepping Into Methods

Let’s use the debugger to trace the logic.

  1. In App.java, set a breakpoint on the line String priority = taskService.getPriorityLabel(urgentTask);.
  2. Start the debugger by clicking the Run and Debug button. Execution will pause at your breakpoint.
  3. At this point, you have used Step Over before. If you use it now, the debugger would execute the getPriorityLabel method and move to the next line in main, hiding what happened inside.
  4. Instead, click the Step Into button (or press F11). The debugger will jump inside the getPriorityLabel method in TaskService.java.

4. The Call Stack

Now that you are inside getPriorityLabel, look at the CALL STACK panel in the debugger view. You should see something like this:

  • getPriorityLabel(Task) line: 9, TaskService
  • main(String[]) line: 8, App

The Call Stack shows the path the program took to get to its current location. It shows that main called getPriorityLabel. The method at the top of the stack is the one currently being executed. This is incredibly useful for understanding your program’s flow.

5. Finding the Logic Error

Now, let’s step through the getPriorityLabel method to find the bug.

  1. You are paused at the first line, String priority = "Low";.
  2. Click Step Over. The priority variable is now "Low".
  3. The next line is if (task.daysUntilDue < 7). The task object has daysUntilDue = 2, so 2 < 7 is true.
  4. Click Step Over. The debugger enters the if block, as expected.
  5. The next line is priority = "Medium";. Click Step Over. The priority variable is now "Medium".
  6. Here is the crucial part. The if block has finished. The else if block is skipped entirely because the first if was true. The program jumps to the return priority; line.

We’ve found the bug! The logic is flawed because any number less than 7 (like 2) will trigger the first if block and never reach the else if block for daysUntilDue < 3.

6. Stepping Out and Fixing the Bug

You can continue stepping, but since we know where we are, let’s use Step Out.

  1. Click the Step Out button (or press Shift+F11). The debugger will finish executing the rest of the getPriorityLabel method and return you to the line in App.java where it was called.
  2. Stop the debugger by clicking the Stop button.

To fix the bug, the order of the if statements needs to be reversed. The most restrictive condition should come first. Update TaskService.java:

// Fix: Check for the most restrictive case first.
if (task.daysUntilDue < 3) {
    priority = "High";
} else if (task.daysUntilDue < 7) {
    priority = "Medium";
}

Run the application again. The output is now correct:

Task: 'Finish report' has priority: High

Congratulations! You have used Step Into and the Call Stack to trace a logic bug across multiple methods and fix it.

4 Reflect and Review

ImportantReflection: 3-2-1

Now that you have completed this exercise, take a moment to reflect on your learning. In your Microsoft Teams Student Notebook, create a new page for this exercise and write down the following:

  • 3 new things you learned about debugging (e.g., Step Into, Call Stack).
  • 2 reasons why the Call Stack is a useful tool.
  • 1 question you still have about debugging multi-method programs and how you will go about learning more about it.

This reflection is for your instructor to review and helps solidify your understanding of the concepts.

TipCheck on Learning

Test your understanding by answering the following questions in your Microsoft Teams Student Notebook. Use the page for this exercise, which may already be under the ‘Exercises’ tab, or create it if needed. This allows your instructor to review your answers.

  1. What is the purpose of the “Step Into” command in the debugger?
  2. What information does the Call Stack provide, and why is it useful?
  3. You are deep inside a chain of method calls (e.g., main -> methodA -> methodB -> methodC) and you want to get back to methodB without stopping the debugger. Which command should you use?
  4. Describe a scenario where using “Step Into” is necessary to find a bug, whereas “Step Over” would hide the problem.
Back to top