11 Minutes
Java debugging: how to debug Java code in IntelliJ, Eclipse, and jdb
Fix Bugs Faster! Log Collection Made Easy
An effective Java debugging strategy lets us pause execution, inspect data, and observe real execution rather than relying on vague assumptions. The complexity of the Java Virtual Machine creates unique challenges, but a focused approach will turn this complexity to our advantage.
This guide will equip you with the tools to do this, looking at:
- How Java debugging works inside the JVM and how it differs from other languages.
- How each of the main Java debugging tools (IntelliJ IDEA, Eclipse, and jdb) vary.
- How to debug Java step-by-step with each of these technologies.
- How to address common debugging issues, like breakpoints not hitting or variables missing.
By the end, you’ll have a practical workflow to debug Java reliably across local and remote environments.
Table of Contents
- What makes Java debugging different
- Java debugging tools
- How to debug Java in IntelliJ IDEA
- How to debug Java in Eclipse
- Debugging Java from the command line with jdb
- Java remote debugging
- Common Java debugging problems
- When the issue is outside the Java backend
- FAQ about Java debugging
- Can Java debugging change application behavior?
- Why does Java debugging show a different line than expected?
- Can I debug Java code inside a Docker container?
- What should I use when Java remote debugging is too risky?
- Why does a Java bug disappear while debugging?
- Should I debug Java tests differently from applications?
What makes Java debugging different
Even if you’re new to Java, you’ll probably know that the Java Virtual Machine (JVM) executes Java bytecode on the underlying machine. This means that Java debugging carries several unique characteristics.
- Multiple versions of the same class may be available to the JVM. If it loads a different version from the one you’re debugging, your breakpoints may not be triggered.
- Methods can be inlined and variables optimized away. Some values won’t appear as expected during debugging.
- Java uses garbage collection to reclaim unreachable objects, but memory leaks can occur if an application unintentionally retains references to objects it no longer needs. When debugging you need to trace these references.
However, Java’s JVM-based execution model also offers an advantage. Java source code compiles to bytecode, and debug metadata allows the debugger to map runtime execution back to the relevant source code – so you can inspect the code you actually wrote.
Java debugging tools
There are several different Java debugging tools available. Each addresses a different debugging environment, from local development where you can pause and control execution, to live systems that may prevent you from interrupting the application.
In practice, selection depends on how much access you have to the running process and whether pausing execution is acceptable.
| Tool | Best for |
|---|---|
| IntelliJ IDEA debugger | Debugging local Java apps and tests with full control over execution and state. |
| Eclipse debugger | Working inside large, existing Eclipse-based projects with structured debug views. |
| jdb | Debugging over SSH or in headless environments where no GUI is available. |
| Bugfender | Investigating production issues without stopping the app using remote logs. |
How to debug Java in IntelliJ IDEA

IntelliJ IDEA is a Java IDE (Integrated Development Environment), developed by JetBrains to write, build, run and debug Java applications in a single workspace.
It integrates project structure, dependencies and build configuration into the development workflow, helping us run and debug the intended application configuration.
The debugger is integrated into the IDE, allowing us to move directly from code to runtime inspection without switching tools.
1. Set up and start a debug session
Before analyzing behavior, make sure the project runs correctly and the debugger is attached to the right configuration.
- Install IntelliJ IDEA and open or import the project.
- Wait for the dependencies to sync and for IntelliJ IDEA to finish indexing the project.
- Set the correct JDK in Project Structure.
- Create or select a Run/Debug configuration.
- Place a breakpoint where you want to inspect execution.
- Start debugging with Run > Debug or Shift + F9.
The application is now running in debug mode and will pause at the breakpoint.
Once paused, move through the code selectively to see how the program executes, and find the point where execution no longer matches the expected path.
- Move forward without entering methods when the current logic is not relevant.
- Step into a method call if you think the call itself is causing the issue.
- Exit a method early if it’s behaving as expected.
- Continue execution to the next breakpoint when needed.
- Follow branches and loops until behavior diverges from expectations.
3. Inspect and validate runtime state
At each pause, verify that the data matches what the code is supposed to produce.
- Check local variables to confirm expected values.
- Expand objects to inspect nested fields and internal state.
- Switch stack frames to compare values across calls.
- Look for nulls, unexpected changes, or incorrect data structures.
- Track how values evolve as execution moves forward.
4. Isolate the root cause
After identifying where behavior breaks, narrow the scope to the exact source of the issue.
- Identify the first line or condition where results become incorrect.
- Trace back to the last point where data was still valid.
- Focus on the smallest piece of logic responsible.
- Ignore unrelated code once the faulty path is clear.
- Rerun the same path to confirm the fix.
How to debug Java in Eclipse

Eclipse is a Java IDE built around JDT (Java Development Tools), with debugging organized through a dedicated Debug Perspective.
The debugging flow is essentially the same as in IntelliJ IDEA: start a debug session, pause execution, step through code, inspect state, and narrow down the cause.
What changes in Eclipse is the interface. Instead of keeping most debugging controls inside the editor, Eclipse separates threads, stack frames, variables, expressions, breakpoints, and console output into different views.
1. Set up and start a debug session
Start by preparing the project and switching into the debugging environment.
- Open or import the project and ensure it builds correctly.
- Add a breakpoint in the target class.
- Start debugging with Debug As > Java Application.
- Switch to the Debug Perspective when prompted.
- Confirm the application has paused and debug views are visible.
2. Use the Debug Perspective
This step is the main difference between Eclipse and IntelliJ IDEA debugging.
- Debug view shows active threads, stack frames, and suspended execution points.
- Variables view shows values for the selected stack frame.
- Expressions view tracks specific values across steps.
- Breakpoints view manages enabled, disabled, and conditional breakpoints.
- Console view keeps application output visible during the session.
From here, you can follow the same debugging process used earlier: step through the relevant path, inspect the state, and identify where behavior changes.
3. Find the cause of the issue
Use Eclipse’s separate views to keep the investigation focused.
- Select the thread and stack frame related to the failing path.
- Compare values in the Variables and Expressions views.
- Check whether the breakpoint is stopping in the expected class and method.
- Use conditional breakpoints if the issue appears only with specific values.
- Rerun the same scenario after the fix.
The key Eclipse-specific advantage is visibility: we can see threads, stack frames, variables, breakpoints, and console output side by side.
Debugging Java from the command line with jdb
jdb is the standard command-line Java debugger, allowing us to attach to a JVM and control execution without a graphical interface.
jdb uses JDWP (Java Debug Wire Protocol) just like IDE debuggers. But everything happens through commands instead of visual panels. This makes it useful in environments where we only have terminal access to call on, such as servers, containers, or remote machines.
1. Start the JVM and attach jdb
Before using jdb, the Java process must expose a debug port.
- Start the application with debugging enabled:
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -jar app.jar
- Attach jdb to the running process:
jdb -attach 5005
- Set a breakpoint and continue execution:
stop in com.example.MyClass.myMethod
cont
The terminal session now controls execution and pauses the JVM at the selected breakpoint.
2. Use jdb commands instead of IDE controls
In jdb, the main difference is command syntax. There are no panels, buttons, or visual object trees.
next # move to next line
step # enter method
cont # continue to next breakpoint
print var # inspect variable
where # show call stack
up # move up stack frame
down # move down stack frame
From here, use the same investigation flow from the IntelliJ section, but translate each action into terminal commands.
3. Find the cause from terminal output
Without an IDE, be sure to write each line carefully and inspect your work thoroughly.
- Use
whereto confirm the current call path. - Use
printto check the value most likely causing the issue. - Use
upanddownwhen the problem depends on a caller frame. - Continue only when the current method or condition looks correct.
The key jdb limitation is visibility: we can debug from almost anywhere, but we need to inspect state more deliberately because nothing is visual.
Java remote debugging

The Java remote debugging workflow lets us connect a debugger to a JVM running on another machine, container, or environment and control its execution as if it were local.
It works through JDWP (Java Debug Wire Protocol), which exposes debugging capabilities like breakpoints, stepping, and variable inspection over a network socket.
This allows us to reproduce and analyze issues in environments that cannot be replicated locally, such as staging servers or containerized deployments.
1. Enable JDWP on the JVM
Before attaching a debugger, the JVM must be configured to listen for debugger connections on a specific port.
- Start the application with JDWP enabled:
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -jar app.jar
- Make sure the port is reachable from the local machine through the network, the container mapping, or an SSH tunnel.
Once you’ve done this, the JVM will be listening for incoming debugger connections.
2. Attach the IDE to the remote JVM
Connect from the IDE using a remote debug configuration.
- Create a Remote JVM Debug configuration in IntelliJ IDEA or a Remote Java Application configuration in Eclipse.
- Set the host and port, such as
localhost:5005. - Start the debug session.
- Confirm the local source code matches the deployed build.
The IDE connects to the remote JVM and maps breakpoints to the local project files.
3. Debug with remote constraints in mind
After attaching, use the same debugging workflow from the IntelliJ or Eclipse section, but remember that actions affect the remote process.
- Avoid pausing critical threads in live environments.
- Bind the debug port safely or use an SSH tunnel.
- Keep sessions focused on one reproducible issue.
- Disable the debug port when the session is finished.
Remote debugging gives us local-style control over a non-local JVM, so the biggest risk is exposing or pausing a running process without clear boundaries.
Common Java debugging problems
When Java debugging throws up curveballs, it’s usually because the debugger is showing the wrong context rather than the wrong information.
| Problem | Fast fix |
|---|---|
| Breakpoints not hitting | Rebuild the project, confirm the deployed class matches the source, and place the breakpoint on executable code. |
| Variables not visible | Pause where the variable is still in scope, switch to the correct stack frame, and check debug metadata. |
| Wrong JVM attached | Match the PID or debug port to the exact process, especially with test runners, containers, or multiple app instances. |
| Source mismatch | Confirm the local source matches the running build, especially after hot reload, shaded JARs, or CI deployments. |
| Thread confusion | Check the active thread before inspecting state, especially in async, web, or scheduled execution paths. |
Remember to fix the context first, then trust what the debugger is telling you.
When the issue is outside the Java backend
Some issues look like Java backend bugs because the API response fails, data appears missing, or users report broken flows. But the real cause may sit in the app layer: a failed request, incorrect state update, device-only bug, or frontend error.
Bugfender (full transparency, this is our own in-house tool) helps teams capture remote logs from real users across:
- Android apps.
- iOS apps.
- React Native apps.
- Flutter apps.
- JavaScript web apps.
If the Java backend returns the right data but the user experience still breaks, Bugfender gives you real visibility into the client-side layer. Try it for free if you want to take a look yourself.
FAQ about Java debugging
Can Java debugging change application behavior?
Yes, Java debugging can change runtime behavior because breakpoints pause threads and affect timing. This matters in concurrent code, scheduled jobs, web requests, and race conditions. If the issue disappears while debugging, compare with logs, thread dumps, or a less intrusive reproduction path.
Why does Java debugging show a different line than expected?
Java debugging can stop on unexpected lines when the running bytecode does not match the local source. This usually happens after stale builds, hot reload, generated code, shaded JARs, or deployment mismatches. Rebuild cleanly and confirm the same artifact is running.
Can I debug Java code inside a Docker container?
Yes, Java code inside Docker can be debugged by exposing the JDWP port and attaching from an IDE or jdb. The container must publish the debug port, and the JVM must start with JDWP enabled. Use this mainly in local or staging environments.
What should I use when Java remote debugging is too risky?
Use logs, metrics, traces, thread dumps, and heap dumps when remote debugging is too risky. These methods do not require pausing live execution, which makes them safer for production systems. Remote debugging should be reserved for controlled environments and short investigations.
Why does a Java bug disappear while debugging?
A Java bug can disappear while debugging when timing changes hide the original issue. This is common with race conditions, thread scheduling, async callbacks, and timeout-sensitive code. In those cases, rely on logs, thread dumps, and repeated reproductions instead of stepping line by line.
Should I debug Java tests differently from applications?
Yes, Java tests are usually easier to debug because the input, state, and execution path are more controlled. Start with the failing test, place a breakpoint before the assertion or failing branch, and inspect the smallest unit of code responsible for the result.
Expect The Unexpected!
Debug Faster With Bugfender