Everyone gets stuck. The difference between an hour and a day is having a method instead of guessing. This post is that method — four steps, in order — plus the errors every Java beginner hits and what each one is really telling you.
1. Read the error. Actually read it.
The most common mistake is pasting an error into a search engine before reading it. Java's messages are specific, and modern ones frequently contain the entire answer:
Cannot invoke "String.length()" because "customer.name" is null
That names the expression, the field, and what was attempted. No search needed. Before you look anything up, answer three questions from the message alone:
- What type of failure is it? A compile error means the code is not valid Java. A runtime exception means it ran and hit something unexpected. These need completely different responses.
- Which line is mine? Read down the stack trace to the first frame in your own package.
- Is there a
Caused by? If so, the last one is the real failure. See Debugging.
2. Reproduce it smaller
A bug inside a 400-line service with a database and three HTTP calls is nearly impossible to reason about. Shrink it until it is not:
class Isolate {
// Instead of debugging this inside the whole request pipeline...
void run() {
// ...reproduce just the failing step, with a hardcoded input
String input = "2026-13-45"; // the value that broke production
try {
LocalDate.parse(input);
} catch (DateTimeParseException e) {
System.out.println("reproduced: " + e.getMessage());
}
}
}
Write it as a test rather than a scratch main. You get a reproduction you can run in
one second, and when you fix it you have a regression test for free.
If you cannot reproduce it, you do not yet understand it — and a fix you cannot verify is a guess. Getting a reliable reproduction is usually most of the work.
3. Change one thing at a time
When something does not work, the temptation is to change four things and re-run. If it then works you have learned nothing, and you are probably carrying three unnecessary changes.
Change one thing. Run. Observe. This is slower for about ten minutes and much faster after that.
The same discipline applies to what you keep: if a change did not help, undo it before trying the next one. Code that accumulates failed attempts becomes its own second problem.
4. Check your assumptions
When the first three steps have not cracked it, the bug is almost always hiding inside something you are certain about. Write down what you believe, then verify each item:
- "The list has items in it."
- "This method is being called."
- "The config value was loaded."
- "The value is what the database contains."
class Check {
void process(List<String> orders, String region) {
// Prove the assumptions rather than trusting them
System.out.println("orders=" + orders.size() + " region=" + region);
if (orders.isEmpty()) {
System.out.println("the loop below never runs — this is probably the bug");
}
for (String order : orders) {
System.out.println("processing " + order);
}
}
}
Two specific things worth verifying early, because they cause bugs that look impossible: are you
comparing objects with == where you needed equals, and is the code running
the version you just edited? A stale build explains a surprising share of "my change had no
effect".
The errors every beginner hits
| Message | What it means | Usual cause |
|---|---|---|
cannot find symbol | a name that does not exist here | typo, missing import, or a variable out of scope |
incompatible types | wrong type on one side | a missing cast, or
int where you needed double |
variable might not have been initialized | read before assigned | a local declared but only set inside an if |
missing return statement | a path that returns nothing | an
if with no else at the end of a method |
unreported exception | a checked exception ignored | catch it or
declare throws |
class X is public, should be declared in a file named X.java | exactly that | the file name does not match the class |
could not find or load main class | the JVM cannot locate it | wrong classpath, or the package was left off the run command |
non-static variable cannot be referenced from a static context | an
instance field used from main | make it static, or create an object |
The last one catches nearly everyone in their first week — see static and final for why.
Searching well
When you do search, the shape of the query matters:
- Search the exception type and the message, not your variable names. Strip out
anything specific to you —
OrderService,customerId— or you will find nothing. - Add the library and version. "spring boot 4" finds different answers from "spring".
- Check the date. Java advice ages badly. An answer that predates 2014 will show
you
Date,Vectorand raw types — see Introduction to Java. - Read the official documentation. The Javadoc for the class you are using is frequently faster than a search result and is never out of date.
If you use an AI assistant, the same rule applies as to any answer: run it before you believe it. Confidently wrong Java compiles about as often as it does not.
Asking for help properly
A good question gets an answer in minutes; a vague one gets nothing. Include four things:
- What you are trying to do — one sentence.
- The smallest code that shows the problem — from step 2, which you already have.
- The full error, including every
Caused by. Not a paraphrase, not a screenshot of half of it. - What you already tried and what happened.
Writing that out solves the problem often enough to be a technique in its own right — the act of explaining it forces you through steps 1 to 4 in order.
Next
Java best practices is next — the habits that stop these problems being created in the first place.