Overview

1 Starting to know your apps

This chapter positions troubleshooting as a core, career-defining skill for Java developers. It reframes “debugging” as just one tool within a broader practice of code investigation: understanding how software actually behaves, comparing it to how it should behave, and isolating the differences. Because most developer time goes into reading and reasoning about existing code rather than writing new lines, sharpening investigation skills yields outsized gains in speed, confidence, and autonomy across tasks like fixing defects, extending features, learning unfamiliar codebases, and avoiding future outages.

The chapter surveys when and how to investigate effectively. It highlights practical techniques such as stepping through code with a debugger for straightforward cases, using profilers to see what executes and where time is spent, adding targeted logging, and introducing controllable stubs to isolate interactions with external systems. It underscores special situations—multithreaded “Heisenbug” behaviors that shift under observation, complex frameworks that obscure control flow, and postmortem work when an app has crashed—where logs, heap dumps, and thread dumps become essential evidence. Beyond bug fixing, investigation supports learning third‑party libraries, improving performance (with I/O hot spots as frequent culprits), enhancing security and maintainability, and making sense of hard‑to‑read or legacy code.

AI is presented as a powerful accelerator, not a substitute for developer judgment: it can summarize evidence, suggest leads, and help plan next steps, while the engineer remains the detective who asks the right questions and validates results. Effective use includes crafting rich, safe prompts, guarding sensitive information, iterating based on responses, and treating outputs as hypotheses to verify. The chapter concludes with outcomes readers can expect: advanced use of debuggers, selecting the right technique for each scenario, profiling to reveal hidden behavior and performance bottlenecks, analyzing memory and thread data for failures, leveraging logging for troubleshooting and security, and applying AI to analyze code, logs, and large datasets to investigate faster and more accurately.

Code investigation is not only about finding problems in software. Today, apps are complex. We often use investigation techniques to understand an app’s behavior or simply to learn new technologies.
Investigating code doesn’t require much physical effort, but debugging sometimes makes you feel like Lara Croft or Indiana Jones. Many developers enjoy the unique sensation of solving the puzzle of a software issue.
Code investigation techniques. Depending on the case, a developer can choose from one or more of these techniques to understand how a certain capability works.
Using a debugger, you can pause the execution before a particular instruction and then observe how the app’s logic changes the data by manually running the instructions step by step.
Identifying code in execution with a profiler. If you don’t know where to start debugging, the profiler can help you to identify the code that is running and give you an idea of where you can use the debugger.
A Heisenberg execution. In a multithreaded app, when a debugger interferes with the app’s execution, it might change how the app behaves. This change doesn’t allow you to correctly investigate the initial app behavior that you wanted to research.
A wrong output can be your app sending erroneous requests to another system component. You may be asked to investigate such a behavior and find its root cause.
You can replace the system component your app calls with a stub. You control the stub to determine where your app sends the request from quickly. You can also use the stub to test your solution after you correct the issue.
Investigating slowness problems with a profiler. The profiler shows you the time spent on each instruction during code execution. This profiler feature is excellent for identifying the root causes of performance problems.
A heap dump is like a map of the heap memory. If you learn how to read it, it gives you invaluable clues about how the app internally processes data. A heap dump helps you investigate memory problems or performance issues. In this example, you can easily find which object fills most of the app’s memory and that the Product and String instances are related.
A thread dump provides details about the threads that were running when the dump was taken. It includes thread states and the stack traces, which tell you what the threads were executing or what blocked them. These details are valuable for investigating why an app is stuck or is having performance problems.

Summary

  • You can use various investigation techniques to analyze software behavior.
  • Depending on your situation, one investigation technique may work better than another. You need to know how to choose the correct approach to make your investigation more efficient. AI tools may prove extremely helpful to help you determine where to start from and what troubleshooting techniques to apply.
  • For some scenarios, using a combination of techniques helps you to identify a problem faster. Learning how each analyzing technique works gives you an excellent advantage in dealing with complex problems.
  • In many cases, developers use investigation techniques to learn new things rather than to solve problems. When learning complex frameworks such as Spring Security or Hibernate, simply reading books or the documentation isn’t enough. An excellent way to accelerate your learning is to debug examples that use a technology you want to better understand.
  • A situation is easier to investigate if you can reproduce it in an environment where you can study it. Reproducing a problem not only helps you find its root cause more easily, but it also helps you to confirm that a solution works when it is applied.

FAQ

What is “troubleshooting” in software development and why is it essential?Troubleshooting is the process of understanding how a system actually behaves, comparing it to how it should behave, and identifying the differences. It makes developers faster and more independent by improving their ability to work on unfamiliar codebases, solve production issues, and spot problems early.
Is debugging the same thing as code investigation?No. Debugging with a debugger is just one investigation technique. Code investigation is broader and includes reading code, using debuggers, profilers, logs, heap/thread dumps, stubs, and postmortem analyses—whichever best fits the situation.
Which techniques does this chapter introduce for understanding Java apps?Key techniques include using a debugger (breakpoints, step-through), profiling (to see what runs and where time is spent), logging, analyzing heap dumps and thread dumps, replacing dependencies with stubs, and collaborating with AI tools to speed up reasoning and exploration.
How should I investigate an unexpected or incorrect output?Start from the kind of output (DB changes, console text, HTTP requests/responses, etc.). If you know where the logic is, use a debugger to step through and observe data changes. If you don’t, use a profiler to locate the executing code path, then drill in with a debugger. Logging can complement both.
What if I don’t know where to put a breakpoint or where to start?Use a profiler to identify which classes/methods are running during the problematic flow. That narrows the search so you can place targeted breakpoints and investigate with a debugger rather than scanning thousands of lines aimlessly.
How do I troubleshoot multithreaded behavior and “Heisenbugs”?Debuggers can change timing and thread interleavings, masking the real issue. Prefer non-intrusive techniques: logging, thread dumps, and profilers configured carefully. Where possible, reduce concurrency (e.g., run with one thread) to reproduce deterministically, then zoom back out to validate under normal concurrency.
How can I diagnose incorrect HTTP requests sent to another service?Identify the code that sends the request. If that’s unclear, profile to find the call site. A useful trick is to replace the external service with a controllable stub that can block, echo, or validate requests. With the stub in place, use the profiler and debugger to inspect how requests are built and sent.
What is a postmortem investigation and what data should I collect?Postmortem investigation happens after an app has crashed or is unresponsive. Since you can’t attach live tools, rely on artifacts: logs, output (if any), heap dumps (for memory issues like OutOfMemoryError), and thread dumps (for stuck or deadlocked threads). These snapshots help you identify root causes and prevent recurrences.
How do I approach performance and slowness problems?Use a profiler to see where time is spent and which code paths are hot. Many slowdowns come from I/O (DB, files, network). Profilers show both call stacks and per-instruction timing so you can pinpoint bottlenecks. Not all performance issues are latency—watch for thread leaks (“zombie” threads), excessive bandwidth, or resource churn.
How can AI help me troubleshoot, and what are best practices?AI can suggest starting points, summarize logs, explain stack traces, and clarify unfamiliar APIs. Best practices: write detailed prompts without sharing sensitive data, ask for step-by-step explanations (not just answers), verify suggestions (AI can hallucinate), and iterate with follow-up prompts. Treat AI as a partner—you remain the investigator.

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Troubleshooting Java, Second Edition ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Troubleshooting Java, Second Edition ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Troubleshooting Java, Second Edition ebook for free