If you cannot figure out why your program crashes or gives the wrong answer, you will never be able to trust your own code. That is why debugging and testing — the skill of methodically finding and fixing errors — is one of the most practical topics in the Oracle Java Foundations 1Z0-811 exam. This chapter teaches you how to use simple print statements and basic debugging techniques to track down problems, so you can fix them quickly and get your program working correctly.
Jump to a section
A simple way to picture Debugging and Testing Java Programs
A head baker in a busy bakery has a loyal customer who orders a special layered cake every week. The baker has a detailed recipe card for this cake, written years ago and passed down from the previous head baker. One week, the customer complains that the cake is dense, not light and fluffy. The baker does not throw the entire recipe away and start from scratch. Instead, she puts on her apron and begins a careful investigation.
She first checks her notes: she remembers making a small change to the recipe that morning, replacing granulated sugar with a liquid honey substitute. She suspects this change might be the culprit. She calls this her 'working theory.' She then writes short notes on the recipe card to track her checks: 'Checked sugar swap — honey adds extra liquid. Batter felt wetter than usual.' These notes are her 'print statements.' She bakes a new test batch with the original granulated sugar. The cake comes out perfectly light and fluffy. She has found the bug: the liquid honey changed the moisture balance. She updates the recipe card permanently: 'Do NOT substitute honey for sugar in this recipe — cake becomes dense.'
The head baker's process maps precisely to debugging Java programs. The recipe is the code. The customer complaint is a bug report — a sign that the program's output is wrong. The baker's working theory is a hypothesis. Her notes on the recipe card are print statements, which a programmer adds to code to check the values of variables at certain points. Her test batch with the original sugar is 'commenting out' the suspected buggy line and running the program again to see if the problem disappears. Her final update to the recipe card is the permanent fix to the code. The baker never needed to crumble the entire cake into flour; she isolated the problem step by step, just as a Java developer uses simple debugging techniques to find and fix errors without rewriting the whole program.
Debugging is the process of finding and removing errors, or 'bugs,' from a computer program. Testing is the process of running a program to check whether it behaves as expected. In Java, these two skills are essential because even a tiny mistake — a missing semicolon, a wrong variable name, or a logic error — can make your entire program produce incorrect results or crash entirely.
The most straightforward debugging technique that beginners learn is using print statements. A print statement is a line of code that outputs a message to the console (the text-based screen where a program's output appears). In Java, you use System.out.println() to print a message. For example, if you want to check the value of a variable called 'score' at a certain point in your program, you can add: System.out.println("The score is: " + score);
When the program runs, it will print 'The score is: 42' (or whatever the current value is) to the console. This lets you see what is happening inside your program as it executes. You can add multiple print statements at different points to trace the flow of execution and see which parts of the code are running and in what order.
Why does this matter? Imagine you wrote a program that calculates the total cost of items in a shopping cart. The program runs, but the final price is too high. Without any way to see what is happening inside the program, you are just guessing. But if you add print statements to check the price of each item before and after a discount is applied, you might discover that the discount is being applied twice, or that a variable is not being reset correctly each time a new item is added. That is the power of print statements: they give you visibility into the hidden behaviour of your code.
Simple debugging goes beyond just printing values. It involves a systematic approach:
Reproduce the bug. First, you must be able to make the error happen again reliably. If you cannot reproduce it, you cannot be sure that any fix actually works.
Isolate the buggy area. Use print statements to narrow down which part of the code is causing the problem. For example, if your program has a large loop that processes 100 items, add a print statement inside the loop to check the value of the loop counter and a key variable. If the values look wrong for the first 20 items but then correct themselves, you know the bug is in the early part of the loop.
Form a hypothesis. Based on what the print statements show, guess what the specific error might be. For example: 'The problem seems to be that I forgot to add 1 to the counter before the loop starts, so the first item is skipped.'
Test your hypothesis. Change the code based on your guess (for example, fix the counter initialisation) and run the program again. If the bug disappears, you found the fix. If not, add more print statements and repeat the process.
Another simple debugging technique is 'commenting out' code. This means turning a line or block of code into a comment by putting two forward slashes // at the start. The Java compiler ignores commented code, so it will not run. By temporarily removing parts of your code, you can check whether a specific section is responsible for the error. For example, if your program gives an incorrect calculation, you can comment out the line that applies a discount and see if the total becomes correct again. If it does, then the bug is likely in the discount logic.
A related concept is the 'stack trace,' which appears when a Java program crashes due to an exception (an unexpected error event). The stack trace is a list of method calls that were active when the error happened. It shows the exact line number in your code where the error occurred, plus the chain of methods that led to it. Reading a stack trace is a critical debugging skill. For example:
Exception in thread "main" java.lang.ArithmeticException: / by zero at Calculator.divide(Calculator.java:15) at Main.main(Main.java:10)
This tells you: an ArithmeticException (dividing by zero) happened inside the divide method of the Calculator class, at line 15 of Calculator.java, and the divide method was called from the Main class's main method at line 10. You can go directly to line 15 of Calculator.java to see what is wrong.
Testing, on the other hand, is about verifying that the program behaves correctly under different conditions. The simplest form of testing is manual testing: running the program with different inputs and checking the outputs against expected results. For example, if you write a method that calculates the area of a rectangle, you should test it with length = 5 and width = 3 and check that the result is 15. You should also test edge cases, such as length = 0 (which should give 0) and negative values (which should be handled gracefully or rejected).
The key takeaway is that debugging and testing are complementary. Testing identifies that a problem exists, while debugging finds the specific cause of that problem and fixes it. Both skills are fundamental for any programmer, and the 1Z0-811 exam tests your ability to apply them using print statements and basic reasoning.
Reproduce the bug
Run the program with the exact input that causes the problem. If you cannot make the bug happen every time, you cannot be sure you have found the right fix later.
Add print statements strategically
Place System.out.println() calls before and after the code you suspect is wrong. Print the values of all variables involved in the calculation or decision.
Run the program and observe the output
Look at what the print statements reveal. Compare the actual values with the values you expected. Identify where the first deviation occurs — that is where the bug is located.
Form a hypothesis and comment out suspect lines
Based on the print output, guess which line or block of code is causing the error. Temporarily turn that line into a comment by adding // at the start, then run the program again.
Apply the permanent fix and remove temporary print statements
Once the bug is found, change the code correctly (fix the variable value, correct the condition, etc.). Remove all the print statements you added for debugging so the program's output is clean.
Test with the original input and additional edge cases
Run the program with the input that originally caused the bug to confirm it works now. Also test with edge cases like zero, negative numbers, and large values to ensure the fix is robust.
An IT professional — let us call her Priya — is a junior Java developer at a small e-commerce company. She has just written a method that calculates the final price of an order after applying a 10% discount for orders over £100. The method takes the original total as input and returns the discounted price. Priya runs a quick test with an order total of £200. She expects the result to be £180 (200 minus 10% of 200). But the program prints £190. Something is wrong.
Priya does not panic. She opens her Java code in an editor and looks at the method. Here is what she sees:
public double calculateDiscountedPrice(double total) { double discount = 0.10; if (total > 100) { double discountedPrice = total - (total * discount); } return discountedPrice; }
Priya adds a print statement right after the discount calculation:
System.out.println("Total before discount: " + total); System.out.println("Discount amount: " + (total * discount)); System.out.println("Discounted price after calculation: " + discountedPrice);
She runs the program with total = 200. The console prints:
Total before discount: 200.0 Discount amount: 20.0 Discounted price after calculation: 180.0
Wait — that looks correct. But why did the method return 190? Priya then adds a print statement just before the return:
System.out.println("Returning value: " + discountedPrice);
She runs it again. This time the console shows:
Total before discount: 200.0 Discount amount: 20.0 Discounted price after calculation: 180.0 Returning value: 0.0
This is a classic trap. Priya realises that the variable discountedPrice is declared inside the if block, so it only exists within that block of code (between the curly braces). Outside the if block, the variable is not defined. The return statement at the end of the method is trying to return a variable that does not exist in that scope. In Java, this causes a compilation error, but her environment might have a default error handling that returns 0.0. The print statement reveals the truth: the variable inside the if block is correct, but the method returns a different, non-existent variable.
Priya applies the fix: she declares discountedPrice before the if block, initialises it to total, and then updates it inside the if block if the condition is met. She also removes the print statements. She runs the test again with total = 200 and gets the correct answer: 180.0.
In a real business scenario, Priya would also write a few more test cases: total = 50 (no discount, should return 50), total = 100 (no discount because condition is > 100, not >=), and total = 0 (should return 0). This ensures her fix works for all edge cases. She might also integrate her code into a build pipeline that automatically runs these tests every time she saves her code, but for the 1Z0-811 exam, the focus is on manual debugging with print statements and simple reasoning.
Priya's story shows exactly what IT professionals do daily: they write code, test it, find bugs, add print statements to understand what is happening, fix the bug, and verify the fix. It is a structured, methodical process — not random guessing.
The 1Z0-811 exam tests your ability to debug simple Java programs using print statements and basic reasoning. The exam does not require you to use a full-fledged debugger tool like Eclipse or IntelliJ's debugger. Instead, it focuses on the mental process of finding and fixing errors. Here is exactly what you need to know.
First, you must be comfortable reading and interpreting System.out.println() output. Questions will show you a short code snippet with print statements and ask what the output will be. These questions test your understanding of how the code executes step by step. For example, you might see:
int x = 5; System.out.println("x is " + x); x = x + 2; System.out.println("x is now " + x);
The answer would be: x is 5 x is now 7
Second, the exam tests your ability to identify common logical errors by tracing through code mentally. You will be given a method that is supposed to calculate something, but it produces an incorrect result. You will need to add a print statement in one of several possible locations to best reveal the bug. The key is to add the print statement where the value is first computed, or where the value is used in a critical comparison.
Third, the exam loves to test scope problems like the one Priya encountered. You will see a method with a variable declared inside an if or loop block, and then the method tries to use that variable outside the block. The exam expects you to recognise that this will cause a compilation error or incorrect behaviour. Print statements can reveal that the variable inside the block is fine, but the program is using a different variable or no variable outside the block.
Fourth, the exam tests your understanding of stack traces. You will be shown a stack trace and asked to identify which line in which class caused the exception. You must read the stack trace from top to bottom. The top line gives the exact exception type, the message, and the line number in the method where the error occurred. The lines below show the call chain — which method called the one that crashed. The exam typically asks: 'Which line in which file caused the error?' or 'What is the name of the exception?' You need to know common exception types like ArithmeticException, NullPointerException, and ArrayIndexOutOfBoundsException.
Fifth, the exam tests your ability to 'comment out' code to isolate bugs. You might be shown a multi-line method and asked which single line, if commented out, would fix the bug or make the output correct. The trap is that commenting out a line might also remove the correct logic for a different scenario, so you must choose the line that is the actual cause of the bug, not just any line that changes the output.
Common traps the exam sets:
Giving a variable the same name inside and outside a block and expecting you to notice that the inner variable shadows the outer one.
Forgetting to initialise a variable before using it in a condition or print statement.
Putting a print statement after a return statement (which never executes because return exits the method).
Mixing up = (assignment) and == (equality comparison) in a condition, which is a common logical error that print statements can reveal.
Key definitions to memorise:
Bug: An error in a program that causes it to produce incorrect or unexpected results.
Debugging: The process of finding and fixing bugs.
Print statement: A line of code (System.out.println()) used to output values to the console for debugging.
Stack trace: A list of method calls that were active when an exception occurred, showing the line numbers.
Exception: An event that disrupts the normal flow of a program's execution.
Commenting out: Turning a line of code into a comment so it is not executed, used to isolate the source of a bug.
Test case: A specific input for which you know the expected output, used to verify that a program works correctly.
The exam will never ask you to write a full program from scratch to debug. Instead, you will analyse short code snippets (usually 5–15 lines) and answer multiple-choice or single-answer questions about what they output, what the bug is, or where the bug is located.
Debugging is the methodical process of finding and fixing errors; testing is the process of running a program to check that it works as expected.
Print statements (System.out.println()) let you see the values of variables and the flow of execution inside your program.
A stack trace shows the exact line number and class where an exception occurred, plus the chain of method calls that led to it.
Commenting out a suspected buggy line of code allows you to test whether removing that line fixes the problem.
Always test your code with edge cases, not just typical inputs, because bugs often hide at boundaries.
After fixing a bug, rerun all your tests to ensure the fix did not break anything else.
These come up on the exam all the time. Here's how to tell them apart.
Syntax Error
Caused by violating Java grammar rules, e.g., missing semicolon or mismatched braces.
Prevents the program from compiling or running at all.
Compiler gives an error message with the line number and description.
Logic Error
Caused by a mistake in the program's logic, e.g., using + instead of *.
Program compiles and runs, but produces incorrect output.
No automatic error message; you must debug to find it.
Print Statement Debugging
You manually add System.out.println() to output variable values.
Works for both logic errors and understanding program flow.
Requires you to guess where to put the print statements.
Stack Trace Analysis
Provided automatically when a runtime exception (crash) occurs.
Only works for runtime exceptions, not for incorrect output.
Gives you the exact line number and method call chain of the crash.
Commenting Out Code
Temporarily disables a line/block by turning it into a comment.
Quick way to test if a specific section is the cause of a bug.
No new code is written; only existing code is disabled.
Writing a New Method
You create a separate method to implement a fix or new behaviour.
More permanent approach that changes the program's structure.
Requires writing new code and ensuring the method is called correctly.
Manual Testing
You run the program by hand with a few test inputs.
Relies on you remembering to test different cases.
Time-consuming and prone to human error for large projects.
Automated Testing
A test framework (like JUnit) runs many test cases automatically.
You write test code that checks expected outputs against actual outputs.
Fast and reliable for regression testing (ensuring new changes do not break old features).
Mistake
If the code compiles (no error messages), my program is bug-free.
Correct
Compilation only checks syntax — whether your code follows Java grammar rules. Logical errors (like using the wrong formula or misplacing a variable) produce wrong results with no compilation error.
Beginners equate a successful compile with a correct program because they have not yet experienced how many silent logic errors exist. They think if the computer does not shout, everything is fine.
Mistake
Adding print statements will fix the bug for you.
Correct
Print statements only show you what values are present — they do not change the program's logic or fix anything. You must interpret the output and manually change the code to fix the underlying issue.
New programmers hope that just putting more System.out.println() calls into their code will somehow magically solve the problem, because they see the output and think the computer is telling them the answer directly.
Mistake
A stack trace is the program's way of telling you you are stupid.
Correct
A stack trace is a helpful diagnostic tool that shows exactly where the error occurred and what chain of method calls led to it. It is the program's way of giving you a map to the bug's location.
The intimidating red text and technical jargon make beginners feel the program is angry at them, so they ignore the stack trace instead of reading it carefully.
Mistake
You should only test your program with 'normal' input, like whole numbers or typical values.
Correct
You must test with edge cases: boundary values, zero, negative numbers, very large numbers, and empty input. These are where most bugs hide.
Beginners naturally test with the happy path because it feels natural, but they do not realise that real-world users will enter all kinds of unexpected data, and robust code must handle those situations without crashing.
Mistake
If you fix one bug, you are done and the program is perfect.
Correct
Fixing one bug can sometimes introduce a new bug, especially if you change a variable or condition that affects other parts of the program. Always retest all relevant scenarios after a fix.
It feels satisfying to fix the obvious problem, and beginners want to move on. They do not understand that code is interconnected, so a change in one place can ripple through the program unexpectedly.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
A syntax error is a grammar mistake in your code (like a missing semicolon) that the compiler catches and prevents your program from running. A logic error is a mistake in your program's logic (like using multiplication instead of addition) that makes the output wrong, but the program still runs.
Yes, you can. If you put a System.out.println() inside a loop, it will print the values at every iteration. Be careful — if the loop runs thousands of times, the console will flood with output. Limit the print statements to only the iterations you need.
Check that you have a main method with the correct signature (public static void main(String[] args)) and that the main method is called automatically when you run the program. Also check that your print statements are inside the main method or are reached by the program's flow.
Start from the top line. It tells you the exception type and message, and gives the file name and line number where the error happened. The lines below show the method calls that led to that line, with the most recent call at the top.
Not usually. For a homework or exam program, removing them is good practice because they clutter the output. In a real application, you should remove debug print statements or use a proper logging library to manage log levels.
Add print statements at the very beginning of the program and at regular intervals throughout. Run the program and see which print statement is the last one to appear before the crash. The bug is somewhere between that line and the next one that did not print.
You've finished Debugging and Testing Java Programs. Continue through the 1Z0-811 study guide to build a complete picture of the exam.
Done with this chapter?