I prefer not to use a debugger, myself, for the simple reason that they are frustrating and don't actually run the same program (breakpoints and such can modify the logic).
There is not a lot of actual science in Computer Science, but finding out why programs go wrong is an exception to that. You have an artifact that is acting in a strange way and you want to first understand what it is doing and why. This is science - a new species of frog with novel behavior. So, use the scientific method. Form an hypothesis about what it is doing and then attempt to verify or rebut the hypothesis. You can use a debugger for this, or simple output statements. If it behaves as expected in one place look elsewhere for the error.
But, my actual practice is to try to avoid this situation as much as possible by using Test-Driven Development. This actually incorporates the science into the process from the beginning, rather than after the fact. It also guarantees, provided you use it correctly, that when an error occurs you don't have a mess requiring an autopsy, but a small glitch that you can immediately fix.
In effect, the test that you write (before you write the code to make it pass), is an hypothesis about the code. If it passes all is well. But if the test fails, you have an improper hypothesis about the actual code. As long as the test is reasonable, it must be the code that is wrong.
This is also a great way to understand an old program - a "dusty deck." What is this program written ten years ago by people no longer in the organization actually doing? How can I make it do what it needs to do now? The answer is to make hypotheses about it and capture them in tests, using a unit testing framework (junit or one of its equivalents). If the tests pass you have increased your understanding since your hypothesis was correct. If it fails, you need to think again. Once you understand it, or at least the relevant parts for the current task, you are in a position to modify it. But do this by writing new tests for the new desired behaviors.
If you program for an hour or two without tests and make an error somewhere you will probably find it difficult to debug. If you make changes to the program, hoping for the best, it will just get worse as the organization of the thing will probably worsen (entropy). But if you program three or four minutes at a time, with tests previously written to capture - in code - your understanding, you are unlikely to ever get frustrated. Unit testing speeds you up. It doesn't slow you down. Even if the number of lines of code in the tests is more than the number of lines of code in the application. Typing isn't what makes programming hard. Understanding is. Capture the understanding.
Of course you need to teach them how to use this technique through demonstration, just as with anything else. And when they come to you with a problem, have them show you the tests.
Note also that if it feels foolish to write a four line test for a three line method that it isn't that I'm not smart enough to write a short method correctly the first time. But when a program is developed incrementally, as it must be, the assumptions I make now may be invalidated later by features added later. A good testing framework doesn't just run the recent test on the recent method. It runs all the tests you have written and so the inconsistencies show up immediately. And of course, it might be either the new thing or the old thing that has to be updated. So write new tests and continue.